diff --git a/BUILD.gn b/BUILD.gn
index 62666aa..4a7cd66 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -162,6 +162,7 @@
       "//chrome/test:unit_tests",
       "//components:components_browsertests",
       "//components/policy:policy_templates",
+      "//components/viz:viz_unittests",
       "//components/viz/common:viz_benchmark",
       "//content/shell:content_shell",
       "//content/test:content_browsertests",
@@ -690,7 +691,10 @@
   }
 
   if (enable_vr) {
-    deps += [ "//chrome/browser/android/vr_shell:vr_common_unittests" ]
+    deps += [
+      "//chrome/browser/android/vr_shell:vr_common_unittests",
+      "//tools/perf/contrib/vr_benchmarks:vr_perf_tests",
+    ]
   }
 }
 
diff --git a/DEPS b/DEPS
index 8894560..9e9f2b1 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8fe24272fa6d2fa9eb2458221ed9852d6ec16f56',
+  'skia_revision': '5449aade6227a1e701ebc24ee683d94a810c9a70',
   # 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': '74cef60193dd753be696e7d839ed00fa07672a35',
+  'v8_revision': '15d0e7ca6ecdade5bf98a1c8e74a9dc681547a1a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '27a606316e1ec4ee7cd45178de40ae1a05235f45',
+  'angle_revision': '70c95fa6ffcbe0914adb5e641288b910ddf1db12',
   # 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.
@@ -60,11 +60,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '83a6bb93fd825b975161546ff92d6fb77a7a9c22',
+  'swiftshader_revision': 'a781af7d5a1930d82d20c0cbc9d66fc8a42391e0',
   # 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': '4183f201c5155717762df48e5d68330b754070f3',
+  'pdfium_revision': '00c3cfdbae074a379cab4edad0e4fa75d6127797',
   # 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.
@@ -76,7 +76,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
-  'google_toolbox_for_mac_revision': '038a2399b20e67ab17685e23ee873a66811fa107',
+  'google_toolbox_for_mac_revision': 'ec72a2bc500a716369c383837bffdc7d2a22855b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -96,7 +96,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': '72646aa580ee22cd0a37c2501a36198966d71dc5',
+  'catapult_revision': '601f74b9033b01e98609f4ebb600c14728298683',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'ec4afbf74a4beebadee3e1b15b43c5d4e3d3bd1c',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '4e16f7070354fa91c1a617ee18335e580a0b8c8c',
 
   'src/third_party/ffmpeg':
     Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'ddb09a0d5aaf6aacf846355b7629953b2496b8ea',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 440d69e..3b7fc37b8 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -774,6 +774,7 @@
 android_library("android_webview_java") {
   java_files = [
     "java/src/org/chromium/android_webview/AndroidProtocolHandler.java",
+    "java/src/org/chromium/android_webview/AutofillActionModeCallback.java",
     "java/src/org/chromium/android_webview/AwActionModeCallback.java",
     "java/src/org/chromium/android_webview/AwAutofillClient.java",
     "java/src/org/chromium/android_webview/AwBrowserContext.java",
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index d4a3b10..03b8edff 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -186,16 +186,10 @@
 
   blacklist_manager_.reset(CreateURLBlackListManager(user_pref_service_.get()));
 
-  // UMA uses randomly-generated GUIDs (globally unique identifiers) to
-  // anonymously identify logs. Every WebView-using app on every device
-  // is given a GUID, stored in this file in the app's data directory.
-  const FilePath guid_file_path =
-      GetPath().Append(FILE_PATH_LITERAL("metrics_guid"));
   AwMetricsServiceClient::GetInstance()->Initialize(
       user_pref_service_.get(),
-      content::BrowserContext::GetDefaultStoragePartition(this)->
-          GetURLRequestContext(),
-      guid_file_path);
+      content::BrowserContext::GetDefaultStoragePartition(this)
+          ->GetURLRequestContext());
 
   web_restriction_provider_.reset(
       new web_restrictions::WebRestrictionsClient());
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 78314275..3bbe432 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -7,6 +7,7 @@
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_browser_terminator.h"
 #include "android_webview/browser/aw_content_browser_client.h"
+#include "android_webview/browser/aw_metrics_service_client.h"
 #include "android_webview/browser/aw_result_codes.h"
 #include "android_webview/browser/aw_safe_browsing_config_helper.h"
 #include "android_webview/browser/deferred_gpu_command_service.h"
@@ -150,6 +151,11 @@
         base::MakeUnique<AwBrowserTerminator>());
   }
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableWebViewFinch)) {
+    AwMetricsServiceClient::GetOrCreateGUID();
+  }
+
   return content::RESULT_CODE_NORMAL_EXIT;
 }
 
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index e57db3a..5d476f2 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/aw_metrics_service_client.h"
 
 #include "android_webview/browser/aw_metrics_log_uploader.h"
+#include "android_webview/common/aw_switches.h"
 #include "android_webview/common/aw_version_info_values.h"
 #include "android_webview/jni/AwMetricsServiceClient_jni.h"
 #include "base/android/build_info.h"
@@ -13,6 +14,8 @@
 #include "base/files/file_util.h"
 #include "base/guid.h"
 #include "base/i18n/rtl.h"
+#include "base/lazy_instance.h"
+#include "base/path_service.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/enabled_state_provider.h"
@@ -38,6 +41,13 @@
 
 const int kUploadIntervalMinutes = 30;
 
+// A GUID in text form is composed of 32 hex digits and 4 hyphens.
+const size_t GUID_SIZE = 32 + 4;
+
+// Client ID of the app, read and cached synchronously at startup
+base::LazyInstance<std::string>::Leaky g_client_id_guid =
+    LAZY_INSTANCE_INITIALIZER;
+
 // Callbacks for metrics::MetricsStateManager::Create. Store/LoadClientInfo
 // allow Windows Chrome to back up ClientInfo. They're no-ops for WebView.
 
@@ -48,30 +58,6 @@
   return client_info;
 }
 
-// A GUID in text form is composed of 32 hex digits and 4 hyphens.
-const size_t GUID_SIZE = 32 + 4;
-
-void GetOrCreateGUID(const base::FilePath guid_file_path, std::string* guid) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-
-  // Try to read an existing GUID.
-  if (base::ReadFileToStringWithMaxSize(guid_file_path, guid, GUID_SIZE)) {
-    if (base::IsValidGUID(*guid))
-      return;
-    else
-      LOG(ERROR) << "Overwriting invalid GUID";
-  }
-
-  // We must write a new GUID.
-  *guid = base::GenerateGUID();
-  if (!base::WriteFile(guid_file_path, guid->c_str(), guid->size())) {
-    // If writing fails, proceed anyway with the new GUID. It won't be persisted
-    // to the next run, but we can still collect metrics with this 1-time GUID.
-    LOG(ERROR) << "Failed to write new GUID";
-  }
-  return;
-}
-
 version_info::Channel GetChannelFromPackageName() {
   JNIEnv* env = base::android::AttachCurrentThread();
   std::string package_name = base::android::ConvertJavaStringToUTF8(
@@ -89,10 +75,47 @@
   return g_lazy_instance_.Pointer();
 }
 
+void AwMetricsServiceClient::GetOrCreateGUID() {
+  // Check for cached GUID
+  if (g_client_id_guid.Get().length() == GUID_SIZE)
+    return;
+
+  // UMA uses randomly-generated GUIDs (globally unique identifiers) to
+  // anonymously identify logs. Every WebView-using app on every device
+  // is given a GUID, stored in this file in the app's data directory.
+  base::FilePath user_data_dir;
+  if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) {
+    LOG(ERROR) << "Failed to get app data directory for Android WebView";
+
+    // Generate a 1-time GUID so metrics can still be collected
+    g_client_id_guid.Get() = base::GenerateGUID();
+    return;
+  }
+
+  const base::FilePath guid_file_path =
+      user_data_dir.Append(FILE_PATH_LITERAL("metrics_guid"));
+
+  // Try to read an existing GUID.
+  if (base::ReadFileToStringWithMaxSize(guid_file_path, &g_client_id_guid.Get(),
+                                        GUID_SIZE)) {
+    if (base::IsValidGUID(g_client_id_guid.Get()))
+      return;
+    LOG(ERROR) << "Overwriting invalid GUID";
+  }
+
+  // We must write a new GUID.
+  g_client_id_guid.Get() = base::GenerateGUID();
+  if (!base::WriteFile(guid_file_path, g_client_id_guid.Get().c_str(),
+                       g_client_id_guid.Get().size())) {
+    // If writing fails, proceed anyway with the new GUID. It won't be persisted
+    // to the next run, but we can still collect metrics with this 1-time GUID.
+    LOG(ERROR) << "Failed to write new GUID";
+  }
+}
+
 void AwMetricsServiceClient::Initialize(
     PrefService* pref_service,
-    net::URLRequestContextGetter* request_context,
-    const base::FilePath guid_file_path) {
+    net::URLRequestContextGetter* request_context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   DCHECK(pref_service_ == nullptr);  // Initialize should only happen once.
@@ -101,22 +124,26 @@
   request_context_ = request_context;
   channel_ = GetChannelFromPackageName();
 
-  std::string* guid = new std::string;
-  // Initialization happens on the UI thread, but getting the GUID should happen
-  // on the file I/O thread. So we start to initialize, then post to get the
-  // GUID, and then pick up where we left off, back on the UI thread, in
-  // InitializeWithGUID.
-  content::BrowserThread::PostTaskAndReply(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&GetOrCreateGUID, guid_file_path, guid),
-      base::Bind(&AwMetricsServiceClient::InitializeWithGUID,
-                 base::Unretained(this), base::Owned(guid)));
+  // If Finch is enabled for WebView the GUID will already have been read at
+  // startup
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableWebViewFinch)) {
+    InitializeWithGUID();
+  } else {
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::FILE, FROM_HERE,
+        base::Bind(&AwMetricsServiceClient::GetOrCreateGUID),
+        base::Bind(&AwMetricsServiceClient::InitializeWithGUID,
+                   base::Unretained(this)));
+  }
 }
 
-void AwMetricsServiceClient::InitializeWithGUID(std::string* guid) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  pref_service_->SetString(metrics::prefs::kMetricsClientID, *guid);
+void AwMetricsServiceClient::InitializeWithGUID() {
+  // The guid must have already been initialized at this point, either
+  // synchronously or asynchronously depending on the kEnableWebViewFinch flag
+  DCHECK_EQ(g_client_id_guid.Get().length(), GUID_SIZE);
+  pref_service_->SetString(metrics::prefs::kMetricsClientID,
+                           g_client_id_guid.Get());
 
   metrics_state_manager_ = metrics::MetricsStateManager::Create(
       pref_service_, this, base::Bind(&StoreClientInfo),
diff --git a/android_webview/browser/aw_metrics_service_client.h b/android_webview/browser/aw_metrics_service_client.h
index 733bd6b..4d24c96 100644
--- a/android_webview/browser/aw_metrics_service_client.h
+++ b/android_webview/browser/aw_metrics_service_client.h
@@ -44,9 +44,12 @@
 
  public:
   static AwMetricsServiceClient* GetInstance();
+
+  // Retrieve the client ID or generate one if none exists
+  static void GetOrCreateGUID();
+
   void Initialize(PrefService* pref_service,
-                  net::URLRequestContextGetter* request_context,
-                  const base::FilePath guid_file_path);
+                  net::URLRequestContextGetter* request_context);
 
   // metrics::EnabledStateProvider implementation
   bool IsConsentGiven() override;
@@ -79,7 +82,7 @@
   AwMetricsServiceClient();
   ~AwMetricsServiceClient() override;
 
-  void InitializeWithGUID(std::string* guid);
+  void InitializeWithGUID();
 
   bool is_enabled_;
   PrefService* pref_service_;
diff --git a/android_webview/common/aw_switches.cc b/android_webview/common/aw_switches.cc
index 04dc0bab..555513c9f 100644
--- a/android_webview/common/aw_switches.cc
+++ b/android_webview/common/aw_switches.cc
@@ -6,6 +6,7 @@
 
 namespace switches {
 
+const char kEnableWebViewFinch[] = "enable-webview-finch";
 const char kSyncOnDrawHardware[] = "sync-on-draw-hardware";
 const char kWebViewSandboxedRenderer[] = "webview-sandboxed-renderer";
 
diff --git a/android_webview/common/aw_switches.h b/android_webview/common/aw_switches.h
index 8ccd320..c41a274 100644
--- a/android_webview/common/aw_switches.h
+++ b/android_webview/common/aw_switches.h
@@ -7,6 +7,7 @@
 
 namespace switches {
 
+extern const char kEnableWebViewFinch[];
 extern const char kSyncOnDrawHardware[];
 extern const char kWebViewSandboxedRenderer[];
 extern const char kWebViewEnableSafeBrowsingSupport[];
diff --git a/android_webview/java/src/org/chromium/android_webview/AutofillActionModeCallback.java b/android_webview/java/src/org/chromium/android_webview/AutofillActionModeCallback.java
new file mode 100644
index 0000000..e033c35
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AutofillActionModeCallback.java
@@ -0,0 +1,62 @@
+// 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.android_webview;
+
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import org.chromium.components.autofill.AutofillProvider;
+
+/**
+ * The class to implement autofill context menu. To match the Android native view behavior, the
+ * autofill context menu only appears when there is no text selected.
+ */
+public class AutofillActionModeCallback implements ActionMode.Callback {
+    private final Context mContext;
+    private final AutofillProvider mAutofillProvider;
+    private final int mAutofillMenuItemTitle;
+    private final int mAutofillMenuItem;
+
+    public AutofillActionModeCallback(Context context, AutofillProvider autofillProvider) {
+        mContext = context;
+        mAutofillProvider = autofillProvider;
+        // TODO(michaelbai): Uses the resource directly after sdk roll to Android O MR1.
+        // crbug.com/740628
+        mAutofillMenuItemTitle =
+                mContext.getResources().getIdentifier("autofill", "string", "android");
+        mAutofillMenuItem = mContext.getResources().getIdentifier("autofill", "id", "android");
+    }
+
+    @Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        return mAutofillMenuItemTitle != 0 && mAutofillMenuItem != 0;
+    }
+
+    @Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        if (mAutofillMenuItemTitle != 0 && mAutofillProvider.shouldQueryAutofillSuggestion()) {
+            MenuItem item = menu.add(
+                    Menu.NONE, mAutofillMenuItem, Menu.CATEGORY_SECONDARY, mAutofillMenuItemTitle);
+            item.setShowAsActionFlags(
+                    MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        if (item.getItemId() == mAutofillMenuItem) {
+            mAutofillProvider.queryAutofillSuggestion();
+            mode.finish();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onDestroyActionMode(ActionMode mode) {}
+}
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 6d442ddd..dabc79b 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -837,6 +837,10 @@
         contentViewCore.setActionModeCallback(
                 new AwActionModeCallback(mContext, this,
                         contentViewCore.getActionModeCallbackHelper()));
+        if (mAutofillProvider != null) {
+            contentViewCore.setNonSelectionActionModeCallback(
+                    new AutofillActionModeCallback(context, mAutofillProvider));
+        }
         contentViewCore.addGestureStateListener(gestureStateListener);
     }
 
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 50e9f01d..46aea901 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -54,6 +54,7 @@
         "//base/android/proguard/chromium_apk.flags",
         "//base/android/proguard/chromium_code.flags",
       ]
+      png_to_webp = true
     }
   }
 }
diff --git a/android_webview/test/embedded_test_server/java/AndroidManifest.xml b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
index aee9ecb9..ccfe776 100644
--- a/android_webview/test/embedded_test_server/java/AndroidManifest.xml
+++ b/android_webview/test/embedded_test_server/java/AndroidManifest.xml
@@ -19,9 +19,11 @@
         <service android:name="org.chromium.android_webview.test.AwEmbeddedTestServerService"
                 android:exported="true"
                 tools:ignore="ExportedService">
-            <intent-filter android:action="org.chromium.net.test.EMBEDDED_TEST_SERVER_SERVICE" />
+            <intent-filter>
+                <action android:name="org.chromium.net.test.EMBEDDED_TEST_SERVER_SERVICE" />
+            </intent-filter>
         </service>
 
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 73ff43a..f853ed85 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1247,6 +1247,7 @@
     "system/tray/system_tray_unittest.cc",
     "system/tray/tray_details_view_unittest.cc",
     "system/tray/tri_view_unittest.cc",
+    "system/tray_tracing_unittest.cc",
     "system/update/tray_update_unittest.cc",
     "system/user/tray_user_unittest.cc",
     "system/web_notification/ash_popup_alignment_delegate_unittest.cc",
diff --git a/ash/mus/shell_delegate_mus.cc b/ash/mus/shell_delegate_mus.cc
index 44eefd4d..f99e7c4 100644
--- a/ash/mus/shell_delegate_mus.cc
+++ b/ash/mus/shell_delegate_mus.cc
@@ -40,7 +40,7 @@
 
 bool ShellDelegateMus::IsMultiProfilesEnabled() const {
   NOTIMPLEMENTED();
-  return false;
+  return true;  // For manual testing of multi-profile under mash.
 }
 
 bool ShellDelegateMus::IsRunningInForcedAppMode() const {
diff --git a/ash/public/interfaces/session_controller.mojom b/ash/public/interfaces/session_controller.mojom
index fe8ba501..e64153de 100644
--- a/ash/public/interfaces/session_controller.mojom
+++ b/ash/public/interfaces/session_controller.mojom
@@ -169,4 +169,7 @@
 
   // Switch the active user to the next or previous user.
   CycleActiveUser(CycleUserDirection direction);
+
+  // Show the multi-profile login UI to add another user to this session.
+  ShowMultiProfileLogin();
 };
diff --git a/ash/public/interfaces/system_tray.mojom b/ash/public/interfaces/system_tray.mojom
index 28aafae..28a103c 100644
--- a/ash/public/interfaces/system_tray.mojom
+++ b/ash/public/interfaces/system_tray.mojom
@@ -28,6 +28,10 @@
   // or |active_directory_managed| is true.
   SetEnterpriseDomain(string enterprise_domain, bool active_directory_managed);
 
+  // Shows or hides an item in the system tray indicating that performance
+  // tracing is running.
+  SetPerformanceTracingIconVisible(bool visible);
+
   // Shows an icon in the system tray indicating that a software update is
   // available. Once shown the icon persists until reboot. |severity| and
   // |factory_reset_required| are used to set the icon, color, and tooltip.
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc
index c5c06417..e16abf70 100644
--- a/ash/session/session_controller.cc
+++ b/ash/session/session_controller.cc
@@ -180,6 +180,11 @@
     client_->CycleActiveUser(direction);
 }
 
+void SessionController::ShowMultiProfileLogin() {
+  if (client_)
+    client_->ShowMultiProfileLogin();
+}
+
 void SessionController::AddObserver(SessionObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h
index d5358db..12d009e 100644
--- a/ash/session/session_controller.h
+++ b/ash/session/session_controller.h
@@ -110,6 +110,9 @@
   // ordering as user sessions are created.
   void CycleActiveUser(CycleUserDirection direction);
 
+  // Show the multi-profile login UI to add another user to this session.
+  void ShowMultiProfileLogin();
+
   void AddObserver(SessionObserver* observer);
   void RemoveObserver(SessionObserver* observer);
 
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 3f7634f7..5f4e813 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -247,7 +247,8 @@
   AddTrayItem(base::MakeUnique<TrayIME>(this));
   tray_accessibility_ = new TrayAccessibility(this);
   AddTrayItem(base::WrapUnique(tray_accessibility_));
-  AddTrayItem(base::MakeUnique<TrayTracing>(this));
+  tray_tracing_ = new TrayTracing(this);
+  AddTrayItem(base::WrapUnique(tray_tracing_));
   AddTrayItem(
       base::MakeUnique<TrayPower>(this, message_center::MessageCenter::Get()));
   tray_network_ = new TrayNetwork(this);
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index fe8a0fd..b522e3d 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -34,6 +34,7 @@
 class TraySupervisedUser;
 class TraySystemInfo;
 class TrayTiles;
+class TrayTracing;
 class TrayUpdate;
 class WebNotificationTray;
 
@@ -264,6 +265,7 @@
   TraySessionLengthLimit* tray_session_length_limit_ = nullptr;
   TraySupervisedUser* tray_supervised_user_ = nullptr;
   TraySystemInfo* tray_system_info_ = nullptr;
+  TrayTracing* tray_tracing_ = nullptr;
   TrayUpdate* tray_update_ = nullptr;
   TrayNightLight* tray_night_light_ = nullptr;
 
diff --git a/ash/system/tray/system_tray_controller.cc b/ash/system/tray/system_tray_controller.cc
index 9e8bc854..2ae89be 100644
--- a/ash/system/tray/system_tray_controller.cc
+++ b/ash/system/tray/system_tray_controller.cc
@@ -199,6 +199,10 @@
   Shell::Get()->system_tray_notifier()->NotifyEnterpriseDomainChanged();
 }
 
+void SystemTrayController::SetPerformanceTracingIconVisible(bool visible) {
+  Shell::Get()->system_tray_notifier()->NotifyTracingModeChanged(visible);
+}
+
 void SystemTrayController::ShowUpdateIcon(mojom::UpdateSeverity severity,
                                           bool factory_reset_required,
                                           mojom::UpdateType update_type) {
diff --git a/ash/system/tray/system_tray_controller.h b/ash/system/tray/system_tray_controller.h
index 8217def..ef10bad 100644
--- a/ash/system/tray/system_tray_controller.h
+++ b/ash/system/tray/system_tray_controller.h
@@ -72,6 +72,7 @@
   void SetUse24HourClock(bool use_24_hour) override;
   void SetEnterpriseDomain(const std::string& enterprise_domain,
                            bool active_directory_managed) override;
+  void SetPerformanceTracingIconVisible(bool visible) override;
   void ShowUpdateIcon(mojom::UpdateSeverity severity,
                       bool factory_reset_required,
                       mojom::UpdateType update_type) override;
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
index c2d3b6e..c21377b 100644
--- a/ash/system/tray/system_tray_delegate.cc
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -12,8 +12,6 @@
 
 void SystemTrayDelegate::Initialize() {}
 
-void SystemTrayDelegate::ShowUserLogin() {}
-
 NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate()
     const {
   return nullptr;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index a363254..e7418fe 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -26,9 +26,6 @@
   // Called after SystemTray has been instantiated.
   virtual void Initialize();
 
-  // Shows login UI to add other users to this session.
-  virtual void ShowUserLogin();
-
   // Returns NetworkingConfigDelegate. May return nullptr.
   virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const;
 
diff --git a/ash/system/tray/system_tray_test_api.h b/ash/system/tray/system_tray_test_api.h
index 4dfed95..43e2614 100644
--- a/ash/system/tray/system_tray_test_api.h
+++ b/ash/system/tray/system_tray_test_api.h
@@ -26,6 +26,7 @@
   TraySupervisedUser* tray_supervised_user() {
     return tray_->tray_supervised_user_;
   }
+  TrayTracing* tray_tracing() { return tray_->tray_tracing_; }
   TraySystemInfo* tray_system_info() { return tray_->tray_system_info_; }
   TrayTiles* tray_tiles() { return tray_->tray_tiles_; }
 
diff --git a/ash/system/tray_tracing_unittest.cc b/ash/system/tray_tracing_unittest.cc
new file mode 100644
index 0000000..f981191
--- /dev/null
+++ b/ash/system/tray_tracing_unittest.cc
@@ -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.
+
+#include "ash/system/tray_tracing.h"
+
+#include "ash/shell.h"
+#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_controller.h"
+#include "ash/system/tray/system_tray_test_api.h"
+#include "ash/test/ash_test_base.h"
+
+namespace ash {
+namespace {
+
+using TrayTracingTest = test::AshTestBase;
+
+// Tests that the icon becomes visible when the tray controller toggles it.
+TEST_F(TrayTracingTest, Visibility) {
+  SystemTray* tray = GetPrimarySystemTray();
+  TrayTracing* tray_tracing = SystemTrayTestApi(tray).tray_tracing();
+
+  // The system starts with tracing off, so the icon isn't visible.
+  EXPECT_FALSE(tray_tracing->tray_view()->visible());
+
+  // Simulate turning on tracing.
+  SystemTrayController* controller = Shell::Get()->system_tray_controller();
+  controller->SetPerformanceTracingIconVisible(true);
+  EXPECT_TRUE(tray_tracing->tray_view()->visible());
+
+  // Simulate turning off tracing.
+  controller->SetPerformanceTracingIconVisible(false);
+  EXPECT_FALSE(tray_tracing->tray_view()->visible());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc
index 238740f..016a912 100644
--- a/ash/system/user/user_view.cc
+++ b/ash/system/user/user_view.cc
@@ -19,7 +19,6 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_controller.h"
-#include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_item_style.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -262,7 +261,7 @@
     // The last item is the "sign in another user" row.
     if (index_in_add_menu == sender->parent()->child_count() - 1) {
       MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY);
-      Shell::Get()->system_tray_delegate()->ShowUserLogin();
+      Shell::Get()->session_controller()->ShowMultiProfileLogin();
     } else {
       const int user_index = index_in_add_menu;
       SwitchUser(user_index);
diff --git a/ash/test/test_session_controller_client.cc b/ash/test/test_session_controller_client.cc
index 3f1b054..8ccd13c 100644
--- a/ash/test/test_session_controller_client.cc
+++ b/ash/test/test_session_controller_client.cc
@@ -179,5 +179,7 @@
   SwitchActiveUser((*it)->user_info->account_id);
 }
 
+void TestSessionControllerClient::ShowMultiProfileLogin() {}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/test/test_session_controller_client.h b/ash/test/test_session_controller_client.h
index 7516e6c..7acd5a1 100644
--- a/ash/test/test_session_controller_client.h
+++ b/ash/test/test_session_controller_client.h
@@ -67,6 +67,7 @@
   void RequestLockScreen() override;
   void SwitchActiveUser(const AccountId& account_id) override;
   void CycleActiveUser(CycleUserDirection direction) override;
+  void ShowMultiProfileLogin() override;
 
  private:
   SessionController* const controller_;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 66297135..9585108 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -500,7 +500,6 @@
     "memory/ref_counted_memory.cc",
     "memory/ref_counted_memory.h",
     "memory/scoped_policy.h",
-    "memory/scoped_vector.h",
     "memory/shared_memory.h",
     "memory/shared_memory_android.cc",
     "memory/shared_memory_handle.cc",
@@ -2097,7 +2096,6 @@
     "memory/ptr_util_unittest.cc",
     "memory/ref_counted_memory_unittest.cc",
     "memory/ref_counted_unittest.cc",
-    "memory/scoped_vector_unittest.cc",
     "memory/shared_memory_mac_unittest.cc",
     "memory/shared_memory_unittest.cc",
     "memory/shared_memory_win_unittest.cc",
diff --git a/base/allocator/allocator_interception_mac.mm b/base/allocator/allocator_interception_mac.mm
index 4980051..68fa5468b 100644
--- a/base/allocator/allocator_interception_mac.mm
+++ b/base/allocator/allocator_interception_mac.mm
@@ -211,7 +211,7 @@
 // === Core Foundation CFAllocators ===
 
 bool CanGetContextForCFAllocator() {
-  return !base::mac::IsOSLaterThan10_12_DontCallThis();
+  return !base::mac::IsOSLaterThan10_13_DontCallThis();
 }
 
 CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index 67d1880..37e5b67 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -147,6 +147,12 @@
 DEFINE_IS_OS_FUNCS(12, IGNORE_DEPLOYMENT_TARGET)
 #endif
 
+#ifdef MAC_OS_X_VERSION_10_13
+DEFINE_IS_OS_FUNCS(13, TEST_DEPLOYMENT_TARGET)
+#else
+DEFINE_IS_OS_FUNCS(13, IGNORE_DEPLOYMENT_TARGET)
+#endif
+
 #undef IGNORE_DEPLOYMENT_TARGET
 #undef TEST_DEPLOYMENT_TARGET
 #undef DEFINE_IS_OS_FUNCS
@@ -154,8 +160,8 @@
 // This should be infrequently used. It only makes sense to use this to avoid
 // codepaths that are very likely to break on future (unreleased, untested,
 // unborn) OS releases, or to log when the OS is newer than any known version.
-inline bool IsOSLaterThan10_12_DontCallThis() {
-  return !IsAtMostOS10_12();
+inline bool IsOSLaterThan10_13_DontCallThis() {
+  return !IsAtMostOS10_13();
 }
 
 // Retrieve the system's model identifier string from the IOKit registry:
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
index ff508f33..266d1c4 100644
--- a/base/mac/mac_util_unittest.mm
+++ b/base/mac/mac_util_unittest.mm
@@ -150,7 +150,10 @@
       EXPECT_FALSE(IsOS10_12());
       EXPECT_FALSE(IsAtLeastOS10_12());
       EXPECT_TRUE(IsAtMostOS10_12());
-      EXPECT_FALSE(IsOSLaterThan10_12_DontCallThis());
+      EXPECT_FALSE(IsOS10_13());
+      EXPECT_FALSE(IsAtLeastOS10_13());
+      EXPECT_TRUE(IsAtMostOS10_13());
+      EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis());
     } else if (minor == 10) {
       EXPECT_FALSE(IsOS10_9());
       EXPECT_FALSE(IsAtMostOS10_9());
@@ -164,7 +167,10 @@
       EXPECT_FALSE(IsOS10_12());
       EXPECT_FALSE(IsAtLeastOS10_12());
       EXPECT_TRUE(IsAtMostOS10_12());
-      EXPECT_FALSE(IsOSLaterThan10_12_DontCallThis());
+      EXPECT_FALSE(IsOS10_13());
+      EXPECT_FALSE(IsAtLeastOS10_13());
+      EXPECT_TRUE(IsAtMostOS10_13());
+      EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis());
     } else if (minor == 11) {
       EXPECT_FALSE(IsOS10_9());
       EXPECT_FALSE(IsAtMostOS10_9());
@@ -178,7 +184,10 @@
       EXPECT_FALSE(IsOS10_12());
       EXPECT_FALSE(IsAtLeastOS10_12());
       EXPECT_TRUE(IsAtMostOS10_12());
-      EXPECT_FALSE(IsOSLaterThan10_12_DontCallThis());
+      EXPECT_FALSE(IsOS10_13());
+      EXPECT_FALSE(IsAtLeastOS10_13());
+      EXPECT_TRUE(IsAtMostOS10_13());
+      EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis());
     } else if (minor == 12) {
       EXPECT_FALSE(IsOS10_9());
       EXPECT_FALSE(IsAtMostOS10_9());
@@ -192,9 +201,29 @@
       EXPECT_TRUE(IsOS10_12());
       EXPECT_TRUE(IsAtMostOS10_12());
       EXPECT_TRUE(IsAtLeastOS10_12());
-      EXPECT_FALSE(IsOSLaterThan10_12_DontCallThis());
+      EXPECT_FALSE(IsOS10_13());
+      EXPECT_FALSE(IsAtLeastOS10_13());
+      EXPECT_TRUE(IsAtMostOS10_13());
+      EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis());
+    } else if (minor == 13) {
+      EXPECT_FALSE(IsOS10_9());
+      EXPECT_FALSE(IsAtMostOS10_9());
+      EXPECT_TRUE(IsAtLeastOS10_9());
+      EXPECT_FALSE(IsOS10_10());
+      EXPECT_FALSE(IsAtMostOS10_10());
+      EXPECT_TRUE(IsAtLeastOS10_10());
+      EXPECT_FALSE(IsOS10_11());
+      EXPECT_FALSE(IsAtMostOS10_11());
+      EXPECT_TRUE(IsAtLeastOS10_11());
+      EXPECT_FALSE(IsOS10_12());
+      EXPECT_FALSE(IsAtMostOS10_12());
+      EXPECT_TRUE(IsAtLeastOS10_12());
+      EXPECT_TRUE(IsOS10_13());
+      EXPECT_TRUE(IsAtLeastOS10_13());
+      EXPECT_TRUE(IsAtMostOS10_13());
+      EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis());
     } else {
-      // Not nine, ten, eleven, or twelve. Ah, ah, ah.
+      // Not nine, ten, eleven, twelve, or thirteen. Ah, ah, ah.
       EXPECT_TRUE(false);
     }
   } else {
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
deleted file mode 100644
index a320b1e..0000000
--- a/base/memory/scoped_vector.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
-#define BASE_MEMORY_SCOPED_VECTOR_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-
-// ScopedVector wraps a vector deleting the elements from its
-// destructor.
-//
-// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
-// we have support for moveable types inside containers).
-template <class T>
-class ScopedVector {
- public:
-  typedef typename std::vector<T*>::allocator_type allocator_type;
-  typedef typename std::vector<T*>::size_type size_type;
-  typedef typename std::vector<T*>::difference_type difference_type;
-  typedef typename std::vector<T*>::pointer pointer;
-  typedef typename std::vector<T*>::const_pointer const_pointer;
-  typedef typename std::vector<T*>::reference reference;
-  typedef typename std::vector<T*>::const_reference const_reference;
-  typedef typename std::vector<T*>::value_type value_type;
-  typedef typename std::vector<T*>::iterator iterator;
-  typedef typename std::vector<T*>::const_iterator const_iterator;
-  typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
-  typedef typename std::vector<T*>::const_reverse_iterator
-      const_reverse_iterator;
-
-  ScopedVector() {}
-  ~ScopedVector() { clear(); }
-  ScopedVector(ScopedVector&& other) { swap(other); }
-
-  ScopedVector& operator=(ScopedVector&& rhs) {
-    swap(rhs);
-    return *this;
-  }
-
-  reference operator[](size_t index) { return v_[index]; }
-  const_reference operator[](size_t index) const { return v_[index]; }
-
-  bool empty() const { return v_.empty(); }
-  size_t size() const { return v_.size(); }
-
-  reverse_iterator rbegin() { return v_.rbegin(); }
-  const_reverse_iterator rbegin() const { return v_.rbegin(); }
-  reverse_iterator rend() { return v_.rend(); }
-  const_reverse_iterator rend() const { return v_.rend(); }
-
-  iterator begin() { return v_.begin(); }
-  const_iterator begin() const { return v_.begin(); }
-  iterator end() { return v_.end(); }
-  const_iterator end() const { return v_.end(); }
-
-  const_reference front() const { return v_.front(); }
-  reference front() { return v_.front(); }
-  const_reference back() const { return v_.back(); }
-  reference back() { return v_.back(); }
-
-  void push_back(T* elem) { v_.push_back(elem); }
-  void push_back(std::unique_ptr<T> elem) { v_.push_back(elem.release()); }
-
-  void pop_back() {
-    DCHECK(!empty());
-    delete v_.back();
-    v_.pop_back();
-  }
-
-  std::vector<T*>& get() { return v_; }
-  const std::vector<T*>& get() const { return v_; }
-  void swap(std::vector<T*>& other) { v_.swap(other); }
-  void swap(ScopedVector<T>& other) { v_.swap(other.v_); }
-  void release(std::vector<T*>* out) {
-    out->swap(v_);
-    v_.clear();
-  }
-
-  void reserve(size_t capacity) { v_.reserve(capacity); }
-
-  // Resize, deleting elements in the disappearing range if we are shrinking.
-  void resize(size_t new_size) {
-    if (v_.size() > new_size) {
-      for (auto it = v_.begin() + new_size; it != v_.end(); ++it)
-        delete *it;
-    }
-    v_.resize(new_size);
-  }
-
-  template<typename InputIterator>
-  void assign(InputIterator begin, InputIterator end) {
-    v_.assign(begin, end);
-  }
-
-  void clear() {
-    for (auto* item : *this)
-      delete item;
-    v_.clear();
-  }
-
-  // Like |clear()|, but doesn't delete any elements.
-  void weak_clear() { v_.clear(); }
-
-  // Lets the ScopedVector take ownership of |x|.
-  iterator insert(iterator position, T* x) {
-    return v_.insert(position, x);
-  }
-
-  iterator insert(iterator position, std::unique_ptr<T> x) {
-    return v_.insert(position, x.release());
-  }
-
-  // Lets the ScopedVector take ownership of elements in [first,last).
-  template<typename InputIterator>
-  void insert(iterator position, InputIterator first, InputIterator last) {
-    v_.insert(position, first, last);
-  }
-
-  iterator erase(iterator position) {
-    delete *position;
-    return v_.erase(position);
-  }
-
-  iterator erase(iterator first, iterator last) {
-    for (auto it = first; it != last; ++it)
-      delete *it;
-    return v_.erase(first, last);
-  }
-
-  // Like |erase()|, but doesn't delete the element at |position|.
-  iterator weak_erase(iterator position) {
-    return v_.erase(position);
-  }
-
-  // Like |erase()|, but doesn't delete the elements in [first, last).
-  iterator weak_erase(iterator first, iterator last) {
-    return v_.erase(first, last);
-  }
-
- private:
-  std::vector<T*> v_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedVector);
-};
-
-#endif  // BASE_MEMORY_SCOPED_VECTOR_H_
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
deleted file mode 100644
index 916dab9..0000000
--- a/base/memory/scoped_vector_unittest.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/scoped_vector.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// The LifeCycleObject notifies its Observer upon construction & destruction.
-class LifeCycleObject {
- public:
-  class Observer {
-   public:
-    virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
-    virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
-
-   protected:
-    virtual ~Observer() {}
-  };
-
-  ~LifeCycleObject() {
-    if (observer_)
-      observer_->OnLifeCycleDestroy(this);
-  }
-
- private:
-  friend class LifeCycleWatcher;
-
-  explicit LifeCycleObject(Observer* observer)
-      : observer_(observer) {
-    observer_->OnLifeCycleConstruct(this);
-  }
-
-  void DisconnectObserver() {
-    observer_ = nullptr;
-  }
-
-  Observer* observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
-};
-
-// The life cycle states we care about for the purposes of testing ScopedVector
-// against objects.
-enum LifeCycleState {
-  LC_INITIAL,
-  LC_CONSTRUCTED,
-  LC_DESTROYED,
-};
-
-// Because we wish to watch the life cycle of an object being constructed and
-// destroyed, and further wish to test expectations against the state of that
-// object, we cannot save state in that object itself. Instead, we use this
-// pairing of the watcher, which observes the object and notifies of
-// construction & destruction. Since we also may be testing assumptions about
-// things not getting freed, this class also acts like a scoping object and
-// deletes the |constructed_life_cycle_object_|, if any when the
-// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
-// changes are:
-//   INITIAL -> CONSTRUCTED -> DESTROYED.
-// Anything more complicated than that should start another test.
-class LifeCycleWatcher : public LifeCycleObject::Observer {
- public:
-  LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
-  ~LifeCycleWatcher() override {
-    // Stop watching the watched object. Without this, the object's destructor
-    // will call into OnLifeCycleDestroy when destructed, which happens after
-    // this destructor has finished running.
-    if (constructed_life_cycle_object_)
-      constructed_life_cycle_object_->DisconnectObserver();
-  }
-
-  // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
-  // LifeCycleWatcher.
-  void OnLifeCycleConstruct(LifeCycleObject* object) override {
-    ASSERT_EQ(LC_INITIAL, life_cycle_state_);
-    ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
-    life_cycle_state_ = LC_CONSTRUCTED;
-    constructed_life_cycle_object_.reset(object);
-  }
-
-  // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
-  // same one we saw constructed.
-  void OnLifeCycleDestroy(LifeCycleObject* object) override {
-    ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
-    LifeCycleObject* constructed_life_cycle_object =
-        constructed_life_cycle_object_.release();
-    ASSERT_EQ(constructed_life_cycle_object, object);
-    life_cycle_state_ = LC_DESTROYED;
-  }
-
-  LifeCycleState life_cycle_state() const { return life_cycle_state_; }
-
-  // Factory method for creating a new LifeCycleObject tied to this
-  // LifeCycleWatcher.
-  LifeCycleObject* NewLifeCycleObject() {
-    return new LifeCycleObject(this);
-  }
-
-  // Returns true iff |object| is the same object that this watcher is tracking.
-  bool IsWatching(LifeCycleObject* object) const {
-    return object == constructed_life_cycle_object_.get();
-  }
-
- private:
-  LifeCycleState life_cycle_state_;
-  std::unique_ptr<LifeCycleObject> constructed_life_cycle_object_;
-
-  DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
-};
-
-TEST(ScopedVectorTest, LifeCycleWatcher) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  LifeCycleObject* object = watcher.NewLifeCycleObject();
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  delete object;
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-}
-
-TEST(ScopedVectorTest, PopBack) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  ScopedVector<LifeCycleObject> scoped_vector;
-  scoped_vector.push_back(watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-  scoped_vector.pop_back();
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-  EXPECT_TRUE(scoped_vector.empty());
-}
-
-TEST(ScopedVectorTest, Clear) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  ScopedVector<LifeCycleObject> scoped_vector;
-  scoped_vector.push_back(watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-  scoped_vector.clear();
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-  EXPECT_TRUE(scoped_vector.empty());
-}
-
-TEST(ScopedVectorTest, WeakClear) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  ScopedVector<LifeCycleObject> scoped_vector;
-  scoped_vector.push_back(watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-  scoped_vector.weak_clear();
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  EXPECT_TRUE(scoped_vector.empty());
-}
-
-TEST(ScopedVectorTest, ResizeShrink) {
-  LifeCycleWatcher first_watcher;
-  EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
-  LifeCycleWatcher second_watcher;
-  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
-  ScopedVector<LifeCycleObject> scoped_vector;
-
-  scoped_vector.push_back(first_watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
-  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
-  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
-  EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
-
-  scoped_vector.push_back(second_watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
-  EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
-  EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
-  EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
-
-  // Test that shrinking a vector deletes elements in the disappearing range.
-  scoped_vector.resize(1);
-  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
-  EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
-  EXPECT_EQ(1u, scoped_vector.size());
-  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
-}
-
-TEST(ScopedVectorTest, ResizeGrow) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  ScopedVector<LifeCycleObject> scoped_vector;
-  scoped_vector.push_back(watcher.NewLifeCycleObject());
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-
-  scoped_vector.resize(5);
-  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  ASSERT_EQ(5u, scoped_vector.size());
-  EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
-  EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
-  EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
-  EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
-  EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
-}
-
-TEST(ScopedVectorTest, Scope) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  {
-    ScopedVector<LifeCycleObject> scoped_vector;
-    scoped_vector.push_back(watcher.NewLifeCycleObject());
-    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-  }
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-}
-
-TEST(ScopedVectorTest, MoveConstruct) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  {
-    ScopedVector<LifeCycleObject> scoped_vector;
-    scoped_vector.push_back(watcher.NewLifeCycleObject());
-    EXPECT_FALSE(scoped_vector.empty());
-    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-
-    ScopedVector<LifeCycleObject> scoped_vector_copy(std::move(scoped_vector));
-    EXPECT_TRUE(scoped_vector.empty());
-    EXPECT_FALSE(scoped_vector_copy.empty());
-    EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
-
-    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  }
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-}
-
-TEST(ScopedVectorTest, MoveAssign) {
-  LifeCycleWatcher watcher;
-  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
-  {
-    ScopedVector<LifeCycleObject> scoped_vector;
-    scoped_vector.push_back(watcher.NewLifeCycleObject());
-    ScopedVector<LifeCycleObject> scoped_vector_assign;
-    EXPECT_FALSE(scoped_vector.empty());
-    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
-
-    scoped_vector_assign = std::move(scoped_vector);
-    EXPECT_TRUE(scoped_vector.empty());
-    EXPECT_FALSE(scoped_vector_assign.empty());
-    EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
-
-    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
-  }
-  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
-}
-
-class DeleteCounter {
- public:
-  explicit DeleteCounter(int* deletes)
-      : deletes_(deletes) {
-  }
-
-  ~DeleteCounter() {
-    (*deletes_)++;
-  }
-
-  void VoidMethod0() {}
-
- private:
-  int* const deletes_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
-};
-
-template <typename T>
-ScopedVector<T> PassThru(ScopedVector<T> scoper) {
-  return scoper;
-}
-
-TEST(ScopedVectorTest, Passed) {
-  int deletes = 0;
-  ScopedVector<DeleteCounter> deleter_vector;
-  deleter_vector.push_back(new DeleteCounter(&deletes));
-  EXPECT_EQ(0, deletes);
-  base::Callback<ScopedVector<DeleteCounter>(void)> callback =
-      base::Bind(&PassThru<DeleteCounter>, base::Passed(&deleter_vector));
-  EXPECT_EQ(0, deletes);
-  ScopedVector<DeleteCounter> result = callback.Run();
-  EXPECT_EQ(0, deletes);
-  result.clear();
-  EXPECT_EQ(1, deletes);
-};
-
-TEST(ScopedVectorTest, InsertRange) {
-  LifeCycleWatcher watchers[5];
-
-  std::vector<LifeCycleObject*> vec;
-  for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
-      ++it) {
-    EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
-    vec.push_back(it->NewLifeCycleObject());
-    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
-  }
-  // Start scope for ScopedVector.
-  {
-    ScopedVector<LifeCycleObject> scoped_vector;
-    scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
-    for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
-        ++it)
-      EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
-  }
-  for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
-    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
-  for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
-    EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
-  for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers);
-      ++it)
-    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
-}
-
-// Assertions for push_back(unique_ptr).
-TEST(ScopedVectorTest, PushBackScopedPtr) {
-  int delete_counter = 0;
-  std::unique_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
-  EXPECT_EQ(0, delete_counter);
-  {
-    ScopedVector<DeleteCounter> v;
-    v.push_back(std::move(elem));
-    EXPECT_EQ(0, delete_counter);
-  }
-  EXPECT_EQ(1, delete_counter);
-}
-
-}  // namespace
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index 4720c8a..bb3a5aa 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -50,11 +50,13 @@
            rebase_path(android_sdk_build_tools, root_build_dir) + CR
   _data += "android_sdk_build_tools_version=$android_sdk_build_tools_version$CR"
   _data +=
+      "android_sdk_tools_version_suffix=$android_sdk_tools_version_suffix$CR"
+  _data +=
       "android_sdk_root=" + rebase_path(android_sdk_root, root_build_dir) + CR
   _data += "android_sdk_version=$android_sdk_version$CR"
   _data += "android_tool_prefix=" +
            rebase_path(android_tool_prefix, root_build_dir) + CR
-  write_file("$root_build_dir/build_vars.txt", _data)
+  write_file(android_build_vars, _data)
 }
 
 # Copy to the lib.unstripped directory so that gdb can easily find it.
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index ba2311a..537a26ad 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -364,7 +364,7 @@
     res_dirs.add(
         os.path.join(self.EntryOutputDir(root_entry), _RES_SUBDIR))
     variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
-    android_manifest = root_entry.Gradle().get('android_manifest')
+    android_manifest = root_entry.DepsInfo().get('android_manifest')
     if not android_manifest:
       android_manifest = self._GenCustomManifest(root_entry)
     variables['android_manifest'] = self._Relativize(
diff --git a/build/android/gyp/merge_manifest.py b/build/android/gyp/merge_manifest.py
new file mode 100755
index 0000000..93769e19
--- /dev/null
+++ b/build/android/gyp/merge_manifest.py
@@ -0,0 +1,100 @@
+#!/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.
+
+"""Merges dependency Android manifests into a root manifest."""
+
+import argparse
+import contextlib
+import os
+import sys
+import tempfile
+import xml.dom.minidom as minidom
+
+from util import build_utils
+
+# Tools library directory - relative to Android SDK root
+SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib')
+
+MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger'
+MANIFEST_MERGER_JARS = [
+  'common{suffix}.jar',
+  'manifest-merger{suffix}.jar',
+  'sdk-common{suffix}.jar',
+  'sdklib{suffix}.jar',
+]
+
+TOOLS_NAMESPACE_PREFIX = 'tools'
+TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
+
+
+@contextlib.contextmanager
+def _PatchedManifest(manifest_path):
+  """Patches an Android manifest to always include the 'tools' namespace
+  declaration, as it is not propagated by the manifest merger from the SDK.
+
+  See https://issuetracker.google.com/issues/63411481
+  """
+  doc = minidom.parse(manifest_path)
+  manifests = doc.getElementsByTagName('manifest')
+  assert len(manifests) == 1
+  manifest = manifests[0]
+
+  manifest.setAttribute('xmlns:%s' % TOOLS_NAMESPACE_PREFIX, TOOLS_NAMESPACE)
+
+  tmp_prefix = os.path.basename(manifest_path)
+  with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest:
+    doc.writexml(patched_manifest)
+    patched_manifest.flush()
+    yield patched_manifest.name
+
+
+def _BuildManifestMergerClasspath(build_vars):
+  return ':'.join([
+    os.path.join(
+      build_vars['android_sdk_root'],
+      SDK_TOOLS_LIB_DIR,
+      jar.format(suffix=build_vars['android_sdk_tools_version_suffix']))
+    for jar in MANIFEST_MERGER_JARS
+  ])
+
+
+def main(argv):
+  argv = build_utils.ExpandFileArgs(argv)
+  parser = argparse.ArgumentParser(description=__doc__)
+  parser.add_argument('--build-vars',
+                      help='Path to GN build vars file',
+                      required=True)
+  parser.add_argument('--root-manifest',
+                      help='Root manifest which to merge into',
+                      required=True)
+  parser.add_argument('--output', help='Output manifest path', required=True)
+  parser.add_argument('--extras',
+                      help='GN list of additional manifest to merge')
+  args = parser.parse_args(argv)
+
+  cmd = [
+    'java',
+    '-cp',
+    _BuildManifestMergerClasspath(build_utils.ReadBuildVars(args.build_vars)),
+    MANIFEST_MERGER_MAIN_CLASS,
+    '--out', args.output,
+  ]
+
+  extras = build_utils.ParseGnList(args.extras)
+  if extras:
+    cmd += ['--libs', ':'.join(extras)]
+
+  with _PatchedManifest(args.root_manifest) as root_manifest:
+    cmd += ['--main', root_manifest]
+    build_utils.CheckOutput(cmd,
+      # https://issuetracker.google.com/issues/63514300: The merger doesn't set
+      # a nonzero exit code for failures.
+      fail_func=lambda returncode, stderr: returncode != 0 or
+        build_utils.IsTimeStale(args.output, [root_manifest] + extras))
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 7b2f48dd..422bfee3 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -21,6 +21,7 @@
 import md5_check  # pylint: disable=relative-import
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+from pylib import constants
 from pylib.constants import host_paths
 
 sys.path.append(os.path.join(os.path.dirname(__file__),
@@ -81,6 +82,14 @@
   return all_files
 
 
+def ReadBuildVars(build_vars_path=None):
+  if not build_vars_path:
+    build_vars_path = os.path.join(constants.GetOutDirectory(),
+                                   "build_vars.txt")
+  with open(build_vars_path) as f:
+    return dict(l.rstrip().split('=', 1) for l in f)
+
+
 def ParseGnList(gn_string):
   """Converts a command-line parameter into a list.
 
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 6eab4b2..c2dee9a 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -410,7 +410,8 @@
     deps_info['gradle_treat_as_prebuilt'] = options.gradle_treat_as_prebuilt
 
   if options.android_manifest:
-    gradle['android_manifest'] = options.android_manifest
+    deps_info['android_manifest'] = options.android_manifest
+
   if options.type in ('java_binary', 'java_library', 'android_apk'):
     if options.java_sources_file:
       deps_info['java_sources_file'] = options.java_sources_file
@@ -706,6 +707,9 @@
     config['uncompressed_locales_java_list'] = (
         _CreateLocalePaksAssetJavaList(config['uncompressed_assets']))
 
+    config['extra_android_manifests'] = filter(None, (
+        d.get('android_manifest') for d in all_resources_deps))
+
     # Collect java resources
     java_resources_jars = [d['java_resources_jar'] for d in all_library_deps
                           if 'java_resources_jar' in d]
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index c93f675..76f03fb 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -771,11 +771,6 @@
                     'Your output directory is likely stale.')
 
 
-def _ReadBuildVars(output_dir):
-  with open(os.path.join(output_dir, 'build_vars.txt')) as f:
-    return dict(l.replace('//', '').rstrip().split('=', 1) for l in f)
-
-
 def main():
   argparser = argparse.ArgumentParser(description='Print APK size metrics.')
   argparser.add_argument('--min-pak-resource-size', type=int, default=20*1024,
@@ -814,7 +809,7 @@
   if not args.no_output_dir:
     constants.CheckOutputDirectory()
     devil_chromium.Initialize()
-    build_vars = _ReadBuildVars(constants.GetOutDirectory())
+    build_vars = build_utils.ReadBuildVars()
     tools_prefix = os.path.join(constants.GetOutDirectory(),
                                 build_vars['android_tool_prefix'])
   else:
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 141d3941..b47c723c 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -45,6 +45,7 @@
     default_android_sdk_root = "//third_party/android_tools/sdk"
     default_android_sdk_version = "26"
     default_android_sdk_build_tools_version = "26.0.0"
+    default_android_sdk_tools_version_suffix = "-25.3.2"
   }
 
   if (!defined(default_lint_android_sdk_root)) {
@@ -104,6 +105,7 @@
     android_sdk_root = default_android_sdk_root
     android_sdk_version = default_android_sdk_version
     android_sdk_build_tools_version = default_android_sdk_build_tools_version
+    android_sdk_tools_version_suffix = default_android_sdk_tools_version_suffix
 
     lint_android_sdk_root = default_lint_android_sdk_root
     lint_android_sdk_version = default_lint_android_sdk_version
@@ -194,6 +196,9 @@
   assert(!(enable_incremental_dx && !is_java_debug))
   assert(!(enable_incremental_javac && !is_java_debug))
 
+  # Path to where selected build variables are written to.
+  android_build_vars = "$root_build_dir/build_vars.txt"
+
   # Host stuff -----------------------------------------------------------------
 
   # Defines the name the Android build gives to the current host CPU
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 7ae86ac..e7a2c5b 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1777,11 +1777,11 @@
       }
       sources = []
     }
-    _android_manifest_deps = []
+    _android_root_manifest_deps = []
     if (defined(invoker.android_manifest_dep)) {
-      _android_manifest_deps = [ invoker.android_manifest_dep ]
+      _android_root_manifest_deps = [ invoker.android_manifest_dep ]
     }
-    _android_manifest = invoker.android_manifest
+    _android_root_manifest = invoker.android_manifest
 
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
     _create_abi_split =
@@ -1820,13 +1820,13 @@
       incremental_install_script_path = _incremental_install_script_path
       resources_zip = resources_zip_path
       build_config = _build_config
-      android_manifest = _android_manifest
+      android_manifest = _android_root_manifest
 
       if (defined(_java_sources_file)) {
         java_sources_file = _java_sources_file
       }
 
-      deps = _android_manifest_deps
+      deps = _android_root_manifest_deps
 
       if (defined(invoker.deps)) {
         possible_config_deps = invoker.deps
@@ -1856,6 +1856,34 @@
       }
     }
 
+    _android_manifest =
+        "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml"
+    android_manifest_target = "${_template_name}__merge_manifests"
+    action(android_manifest_target) {
+      script = "//build/android/gyp/merge_manifest.py"
+
+      sources = [
+        _android_root_manifest,
+      ]
+
+      outputs = [
+        _android_manifest,
+      ]
+
+      args = [
+        "--build-vars",
+        rebase_path(android_build_vars, root_build_dir),
+        "--root-manifest",
+        rebase_path(_android_root_manifest, root_build_dir),
+        "--output",
+        rebase_path(_android_manifest, root_build_dir),
+        "--extras",
+        "@FileArg($_rebased_build_config:extra_android_manifests)",
+      ]
+
+      deps = _android_root_manifest_deps + [ ":$build_config_target" ]
+    }
+
     _final_deps = []
 
     if (enable_multidex) {
@@ -1886,7 +1914,10 @@
       }
 
       build_config = _build_config
-      deps = _android_manifest_deps + [ ":$build_config_target" ]
+      deps = [
+        ":$android_manifest_target",
+        ":$build_config_target",
+      ]
       if (defined(invoker.deps)) {
         deps += invoker.deps
       }
@@ -1992,7 +2023,10 @@
       supports_android = true
       requires_android = true
       override_build_config = _build_config
-      deps = _android_manifest_deps + [ ":$build_config_target" ]
+      deps = [
+        ":$android_manifest_target",
+        ":$build_config_target",
+      ]
 
       android_manifest = _android_manifest
       srcjar_deps = _srcjar_deps
@@ -2268,17 +2302,19 @@
       keystore_password = _keystore_password
 
       # Incremental apk does not use native libs nor final dex.
-      incremental_deps = deps + _android_manifest_deps + [
+      incremental_deps = deps + [
+                           ":$android_manifest_target",
                            ":$build_config_target",
                            ":$process_resources_target",
                          ]
 
       # This target generates the input file _all_resources_zip_path.
-      deps += _android_manifest_deps + [
-                ":$build_config_target",
-                ":$process_resources_target",
-                ":$final_dex_target_name",
-              ]
+      deps += [
+        ":$android_manifest_target",
+        ":$build_config_target",
+        ":$final_dex_target_name",
+        ":$process_resources_target",
+      ]
 
       if ((_native_libs_deps != [] ||
            _extra_native_libs_even_when_incremental != []) &&
@@ -2311,7 +2347,9 @@
         out_manifest =
             "$gen_dir/split-manifests/${android_app_abi}/AndroidManifest.xml"
         split_name = "abi_${android_app_abi}"
-        deps = _android_manifest_deps
+        deps = [
+          ":$android_manifest_target",
+        ]
       }
 
       _apk_rule = "${_template_name}__split_apk_abi_${android_app_abi}"
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 2fe2405..76fd6498 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -140,8 +140,6 @@
     "output/bsp_tree.h",
     "output/bsp_walk_action.cc",
     "output/bsp_walk_action.h",
-    "output/buffer_to_texture_target_map.cc",
-    "output/buffer_to_texture_target_map.h",
     "output/ca_layer_overlay.cc",
     "output/ca_layer_overlay.h",
     "output/color_lut_cache.cc",
@@ -295,8 +293,6 @@
     "resources/resource_pool.h",
     "resources/resource_provider.cc",
     "resources/resource_provider.h",
-    "resources/resource_settings.cc",
-    "resources/resource_settings.h",
     "resources/resource_util.h",
     "resources/returned_resource.h",
     "resources/scoped_resource.cc",
@@ -682,6 +678,7 @@
     "//cc/paint",
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
+    "//components/viz/common",
     "//gpu/command_buffer/client:gles2_c_lib",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/command_buffer/common:gles2_utils",
@@ -762,7 +759,6 @@
     "layers/viewport_unittest.cc",
     "output/begin_frame_args_unittest.cc",
     "output/bsp_tree_unittest.cc",
-    "output/buffer_to_texture_target_map_unittest.cc",
     "output/context_cache_controller_unittest.cc",
     "output/gl_renderer_unittest.cc",
     "output/layer_quad_unittest.cc",
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 4c25f7ee..dfa2f2b 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -18,7 +18,6 @@
 #include "cc/base/math_util.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/picture_layer.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/quads/draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/test/begin_frame_args_test.h"
@@ -39,6 +38,7 @@
 #include "cc/tiles/tiling_set_raster_queue_all.h"
 #include "cc/tiles/tiling_set_raster_queue_required.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
@@ -82,7 +82,7 @@
     settings.layer_transforms_should_scale_layer_contents = true;
     settings.create_low_res_tiling = true;
     settings.resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
 
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index 47c0fc7..e102cbfc 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -8,7 +8,7 @@
 #include <stddef.h>
 
 #include "cc/cc_export.h"
-#include "cc/resources/resource_settings.h"
+#include "components/viz/common/resources/resource_settings.h"
 
 namespace cc {
 
@@ -18,7 +18,7 @@
   RendererSettings(const RendererSettings& other);
   ~RendererSettings();
 
-  ResourceSettings resource_settings;
+  viz::ResourceSettings resource_settings;
   bool allow_antialiasing = true;
   bool force_antialiasing = false;
   bool force_blending_with_shaders = false;
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h
index 2101c1aa..6f1f1a9 100644
--- a/cc/paint/paint_flags.h
+++ b/cc/paint/paint_flags.h
@@ -177,7 +177,7 @@
   }
 
   ALWAYS_INLINE void setShader(sk_sp<PaintShader> shader) {
-    paint_.setShader(shader ? shader->sk_shader() : nullptr);
+    paint_.setShader(shader ? shader->GetSkShader() : nullptr);
   }
   ALWAYS_INLINE SkPathEffect* getPathEffect() const {
     return paint_.getPathEffect();
diff --git a/cc/paint/paint_shader.cc b/cc/paint/paint_shader.cc
index 19cf600..daf2a56c 100644
--- a/cc/paint/paint_shader.cc
+++ b/cc/paint/paint_shader.cc
@@ -11,7 +11,12 @@
 namespace cc {
 
 sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) {
-  return sk_sp<PaintShader>(new PaintShader(nullptr, color));
+  sk_sp<PaintShader> shader(new PaintShader(kColor));
+
+  // Just one color. Store it in the fallback color. Easy.
+  shader->fallback_color_ = color;
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
@@ -22,25 +27,36 @@
                                                    uint32_t flags,
                                                    const SkMatrix* local_matrix,
                                                    SkColor fallback_color) {
-  return sk_sp<PaintShader>(
-      new PaintShader(SkGradientShader::MakeLinear(points, colors, pos, count,
-                                                   mode, flags, local_matrix),
-                      fallback_color));
+  sk_sp<PaintShader> shader(new PaintShader(kLinearGradient));
+
+  // There are always two points, the start and the end.
+  shader->start_point_ = points[0];
+  shader->end_point_ = points[1];
+  shader->SetColorsAndPositions(colors, pos, count);
+  shader->SetMatrixAndTiling(local_matrix, mode, mode);
+  shader->SetFlagsAndFallback(flags, fallback_color);
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
                                                    SkScalar radius,
                                                    const SkColor colors[],
                                                    const SkScalar pos[],
-                                                   int color_count,
+                                                   int count,
                                                    SkShader::TileMode mode,
                                                    uint32_t flags,
                                                    const SkMatrix* local_matrix,
                                                    SkColor fallback_color) {
-  return sk_sp<PaintShader>(new PaintShader(
-      SkGradientShader::MakeRadial(center, radius, colors, pos, color_count,
-                                   mode, flags, local_matrix),
-      fallback_color));
+  sk_sp<PaintShader> shader(new PaintShader(kRadialGradient));
+
+  shader->center_ = center;
+  shader->start_radius_ = shader->end_radius_ = radius;
+  shader->SetColorsAndPositions(colors, pos, count);
+  shader->SetMatrixAndTiling(local_matrix, mode, mode);
+  shader->SetFlagsAndFallback(flags, fallback_color);
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
@@ -50,16 +66,22 @@
     SkScalar end_radius,
     const SkColor colors[],
     const SkScalar pos[],
-    int color_count,
+    int count,
     SkShader::TileMode mode,
     uint32_t flags,
     const SkMatrix* local_matrix,
     SkColor fallback_color) {
-  return sk_sp<PaintShader>(
-      new PaintShader(SkGradientShader::MakeTwoPointConical(
-                          start, start_radius, end, end_radius, colors, pos,
-                          color_count, mode, flags, local_matrix),
-                      fallback_color));
+  sk_sp<PaintShader> shader(new PaintShader(kTwoPointConicalGradient));
+
+  shader->start_point_ = start;
+  shader->end_point_ = end;
+  shader->start_radius_ = start_radius;
+  shader->end_radius_ = end_radius;
+  shader->SetColorsAndPositions(colors, pos, count);
+  shader->SetMatrixAndTiling(local_matrix, mode, mode);
+  shader->SetFlagsAndFallback(flags, fallback_color);
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
@@ -70,18 +92,27 @@
                                                   uint32_t flags,
                                                   const SkMatrix* local_matrix,
                                                   SkColor fallback_color) {
-  return sk_sp<PaintShader>(new PaintShader(
-      SkGradientShader::MakeSweep(cx, cy, colors, pos, color_count, flags,
-                                  local_matrix),
-      fallback_color));
+  sk_sp<PaintShader> shader(new PaintShader(kSweepGradient));
+
+  shader->center_ = SkPoint::Make(cx, cy);
+  shader->SetColorsAndPositions(colors, pos, color_count);
+  shader->SetMatrixAndTiling(local_matrix, SkShader::kClamp_TileMode,
+                             SkShader::kClamp_TileMode);
+  shader->SetFlagsAndFallback(flags, fallback_color);
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakeImage(sk_sp<const SkImage> image,
                                           SkShader::TileMode tx,
                                           SkShader::TileMode ty,
                                           const SkMatrix* local_matrix) {
-  return sk_sp<PaintShader>(new PaintShader(
-      image->makeShader(tx, ty, local_matrix), SK_ColorTRANSPARENT));
+  sk_sp<PaintShader> shader(new PaintShader(kImage));
+
+  shader->image_ = std::move(image);
+  shader->SetMatrixAndTiling(local_matrix, tx, ty);
+
+  return shader;
 }
 
 sk_sp<PaintShader> PaintShader::MakePaintRecord(sk_sp<PaintRecord> record,
@@ -89,18 +120,98 @@
                                                 SkShader::TileMode tx,
                                                 SkShader::TileMode ty,
                                                 const SkMatrix* local_matrix) {
-  return sk_sp<PaintShader>(new PaintShader(
-      SkShader::MakePictureShader(ToSkPicture(std::move(record), tile), tx, ty,
-                                  local_matrix, nullptr),
-      SK_ColorTRANSPARENT));
+  sk_sp<PaintShader> shader(new PaintShader(kPaintRecord));
+
+  shader->record_ = std::move(record);
+  shader->tile_ = tile;
+  shader->SetMatrixAndTiling(local_matrix, tx, ty);
+
+  return shader;
 }
 
-PaintShader::PaintShader(sk_sp<SkShader> shader, SkColor fallback_color)
-    : sk_shader_(shader ? std::move(shader)
-                        : SkShader::MakeColorShader(fallback_color)) {
-  DCHECK(sk_shader_);
-}
-
+PaintShader::PaintShader(Type type) : shader_type_(type) {}
 PaintShader::~PaintShader() = default;
 
+sk_sp<SkShader> PaintShader::GetSkShader() const {
+  if (cached_shader_)
+    return cached_shader_;
+
+  switch (shader_type_) {
+    case kColor:
+      // This will be handled by the fallback check below.
+      break;
+    case kLinearGradient: {
+      SkPoint points[2] = {start_point_, end_point_};
+      cached_shader_ = SkGradientShader::MakeLinear(
+          points, colors_.data(),
+          positions_.empty() ? nullptr : positions_.data(),
+          static_cast<int>(colors_.size()), tx_, flags_,
+          local_matrix_ ? &*local_matrix_ : nullptr);
+      break;
+    }
+    case kRadialGradient:
+      cached_shader_ = SkGradientShader::MakeRadial(
+          center_, start_radius_, colors_.data(),
+          positions_.empty() ? nullptr : positions_.data(),
+          static_cast<int>(colors_.size()), tx_, flags_,
+          local_matrix_ ? &*local_matrix_ : nullptr);
+      break;
+    case kTwoPointConicalGradient:
+      cached_shader_ = SkGradientShader::MakeTwoPointConical(
+          start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
+          positions_.empty() ? nullptr : positions_.data(),
+          static_cast<int>(colors_.size()), tx_, flags_,
+          local_matrix_ ? &*local_matrix_ : nullptr);
+      break;
+    case kSweepGradient:
+      cached_shader_ = SkGradientShader::MakeSweep(
+          center_.x(), center_.y(), colors_.data(),
+          positions_.empty() ? nullptr : positions_.data(),
+          static_cast<int>(colors_.size()), flags_,
+          local_matrix_ ? &*local_matrix_ : nullptr);
+      break;
+    case kImage:
+      cached_shader_ = image_->makeShader(
+          tx_, ty_, local_matrix_ ? &*local_matrix_ : nullptr);
+      break;
+    case kPaintRecord:
+      cached_shader_ = SkShader::MakePictureShader(
+          ToSkPicture(record_, tile_), tx_, ty_,
+          local_matrix_ ? &*local_matrix_ : nullptr, nullptr);
+      break;
+    case kShaderCount:
+      NOTREACHED();
+      break;
+  }
+
+  // If we didn't create a shader for whatever reason, create a fallback color
+  // one.
+  if (!cached_shader_)
+    cached_shader_ = SkShader::MakeColorShader(fallback_color_);
+  return cached_shader_;
+}
+
+void PaintShader::SetColorsAndPositions(const SkColor* colors,
+                                        const SkScalar* positions,
+                                        int count) {
+  DCHECK_GE(count, 2);
+  colors_.assign(colors, colors + count);
+  if (positions)
+    positions_.assign(positions, positions + count);
+}
+
+void PaintShader::SetMatrixAndTiling(const SkMatrix* matrix,
+                                     SkShader::TileMode tx,
+                                     SkShader::TileMode ty) {
+  if (matrix)
+    local_matrix_ = *matrix;
+  tx_ = tx;
+  ty_ = ty;
+}
+
+void PaintShader::SetFlagsAndFallback(uint32_t flags, SkColor fallback_color) {
+  flags_ = flags;
+  fallback_color_ = fallback_color;
+}
+
 }  // namespace cc
diff --git a/cc/paint/paint_shader.h b/cc/paint/paint_shader.h
index 6dd468c..1385f59 100644
--- a/cc/paint/paint_shader.h
+++ b/cc/paint/paint_shader.h
@@ -6,7 +6,9 @@
 #define CC_PAINT_PAINT_SHADER_H_
 
 #include <memory>
+#include <vector>
 
+#include "base/optional.h"
 #include "cc/paint/paint_export.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkScalar.h"
@@ -22,9 +24,9 @@
   static sk_sp<PaintShader> MakeColor(SkColor color);
 
   static sk_sp<PaintShader> MakeLinearGradient(
-      const SkPoint points[],
-      const SkColor colors[],
-      const SkScalar pos[],
+      const SkPoint* points,
+      const SkColor* colors,
+      const SkScalar* pos,
       int count,
       SkShader::TileMode mode,
       uint32_t flags = 0,
@@ -78,12 +80,61 @@
 
   ~PaintShader() override;
 
-  const sk_sp<SkShader>& sk_shader() const { return sk_shader_; }
+  SkMatrix GetLocalMatrix() const {
+    return local_matrix_ ? *local_matrix_ : SkMatrix::I();
+  }
 
  private:
-  PaintShader(sk_sp<SkShader> shader, SkColor fallback_color);
+  friend class PaintFlags;
 
-  sk_sp<SkShader> sk_shader_;
+  enum Type {
+    kColor,
+    kLinearGradient,
+    kRadialGradient,
+    kTwoPointConicalGradient,
+    kSweepGradient,
+    kImage,
+    kPaintRecord,
+    kShaderCount
+  };
+
+  explicit PaintShader(Type type);
+
+  sk_sp<SkShader> GetSkShader() const;
+
+  void SetColorsAndPositions(const SkColor* colors,
+                             const SkScalar* positions,
+                             int count);
+  void SetMatrixAndTiling(const SkMatrix* matrix,
+                          SkShader::TileMode tx,
+                          SkShader::TileMode ty);
+  void SetFlagsAndFallback(uint32_t flags, SkColor fallback_color);
+
+  Type shader_type_ = kShaderCount;
+
+  uint32_t flags_ = 0;
+  SkScalar end_radius_ = 0;
+  SkScalar start_radius_ = 0;
+  SkShader::TileMode tx_ = SkShader::kClamp_TileMode;
+  SkShader::TileMode ty_ = SkShader::kClamp_TileMode;
+  SkColor fallback_color_ = SK_ColorTRANSPARENT;
+
+  base::Optional<SkMatrix> local_matrix_;
+  SkPoint center_ = SkPoint::Make(0, 0);
+  SkRect tile_ = SkRect::MakeEmpty();
+
+  SkPoint start_point_ = SkPoint::Make(0, 0);
+  SkPoint end_point_ = SkPoint::Make(0, 0);
+
+  sk_sp<const SkImage> image_;
+  sk_sp<PaintRecord> record_;
+
+  std::vector<SkColor> colors_;
+  std::vector<SkScalar> positions_;
+
+  mutable sk_sp<SkShader> cached_shader_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintShader);
 };
 
 }  // namespace cc
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index d4feafe..3d022fa 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -369,7 +369,7 @@
     ContextProvider* compositor_context_provider,
     bool delegated_sync_points_required,
     bool enable_color_correct_rasterization,
-    const ResourceSettings& resource_settings)
+    const viz::ResourceSettings& resource_settings)
     : default_resource_type(resource_settings.use_gpu_memory_buffer_resources
                                 ? RESOURCE_TYPE_GPU_MEMORY_BUFFER
                                 : RESOURCE_TYPE_GL_TEXTURE),
@@ -416,7 +416,7 @@
     BlockingTaskRunner* blocking_main_thread_task_runner,
     bool delegated_sync_points_required,
     bool enable_color_correct_rasterization,
-    const ResourceSettings& resource_settings)
+    const viz::ResourceSettings& resource_settings)
     : settings_(compositor_context_provider,
                 delegated_sync_points_required,
                 enable_color_correct_rasterization,
@@ -2039,7 +2039,7 @@
                                                viz::ResourceFormat format) {
   gfx::BufferFormat buffer_format = BufferFormat(format);
   auto found = buffer_to_texture_target_map_.find(
-      BufferToTextureTargetKey(usage, buffer_format));
+      viz::BufferToTextureTargetKey(usage, buffer_format));
   DCHECK(found != buffer_to_texture_target_map_.end());
   return found->second;
 }
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 49b27250..a53db3d7 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -30,13 +30,13 @@
 #include "cc/output/output_surface.h"
 #include "cc/output/renderer_settings.h"
 #include "cc/resources/release_callback_impl.h"
-#include "cc/resources/resource_settings.h"
 #include "cc/resources/return_callback.h"
 #include "cc/resources/shared_bitmap.h"
 #include "cc/resources/single_release_callback_impl.h"
 #include "cc/resources/texture_mailbox.h"
 #include "cc/resources/transferable_resource.h"
 #include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/resources/resource_settings.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -87,7 +87,7 @@
                    BlockingTaskRunner* blocking_main_thread_task_runner,
                    bool delegated_sync_points_required,
                    bool enable_color_correct_rasterization,
-                   const ResourceSettings& resource_settings);
+                   const viz::ResourceSettings& resource_settings);
   ~ResourceProvider() override;
 
   void Initialize();
@@ -766,7 +766,7 @@
     Settings(ContextProvider* compositor_context_provider,
              bool delegated_sync_points_needed,
              bool enable_color_correct_rasterization,
-             const ResourceSettings& resource_settings);
+             const viz::ResourceSettings& resource_settings);
 
     int max_texture_size = 0;
     bool use_texture_storage_ext = false;
@@ -793,7 +793,7 @@
   ChildMap children_;
   scoped_refptr<Fence> current_read_lock_fence_;
   std::unique_ptr<TextureIdAllocator> texture_id_allocator_;
-  BufferToTextureTargetMap buffer_to_texture_target_map_;
+  viz::BufferToTextureTargetMap buffer_to_texture_target_map_;
 
   // Keep track of whether deleted resources should be batched up or returned
   // immediately.
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index b8b9df6..b9cf56c 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/resources/returned_resource.h"
 #include "cc/resources/shared_bitmap_manager.h"
 #include "cc/resources/single_release_callback.h"
@@ -28,6 +27,7 @@
 #include "cc/test/test_texture.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/blocking_task_runner.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -104,15 +104,15 @@
   return shared_bitmap;
 }
 
-static ResourceSettings CreateResourceSettings(
+static viz::ResourceSettings CreateResourceSettings(
     size_t texture_id_allocation_chunk_size = 1) {
-  ResourceSettings resource_settings;
+  viz::ResourceSettings resource_settings;
   resource_settings.texture_id_allocation_chunk_size =
       texture_id_allocation_chunk_size;
   resource_settings.use_gpu_memory_buffer_resources =
       kUseGpuMemoryBufferResources;
   resource_settings.buffer_to_texture_target_map =
-      DefaultBufferToTextureTargetMapForTesting();
+      viz::DefaultBufferToTextureTargetMapForTesting();
   return resource_settings;
 }
 
@@ -462,7 +462,7 @@
     child_gpu_memory_buffer_manager_ =
         gpu_memory_buffer_manager_->CreateClientGpuMemoryBufferManager();
 
-    ResourceSettings resource_settings = CreateResourceSettings();
+    viz::ResourceSettings resource_settings = CreateResourceSettings();
     resource_provider_ = base::MakeUnique<ResourceProvider>(
         context_provider_.get(), shared_bitmap_manager_.get(),
         gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(),
@@ -2105,7 +2105,7 @@
     child_context_provider->BindToCurrentThread();
     auto shared_bitmap_manager = base::MakeUnique<TestSharedBitmapManager>();
 
-    ResourceSettings resource_settings = CreateResourceSettings();
+    viz::ResourceSettings resource_settings = CreateResourceSettings();
     std::unique_ptr<ResourceProvider> child_resource_provider(
         base::MakeUnique<ResourceProvider>(
             child_context_provider.get(), shared_bitmap_manager.get(), nullptr,
diff --git a/cc/test/fake_resource_provider.h b/cc/test/fake_resource_provider.h
index fb46f1f..8123cd0b 100644
--- a/cc/test/fake_resource_provider.h
+++ b/cc/test/fake_resource_provider.h
@@ -8,8 +8,8 @@
 #include <stddef.h>
 
 #include "base/memory/ptr_util.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/resources/resource_provider.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "ui/gfx/buffer_types.h"
 
 namespace cc {
@@ -19,10 +19,10 @@
   static std::unique_ptr<FakeResourceProvider> Create(
       ContextProvider* context_provider,
       SharedBitmapManager* shared_bitmap_manager) {
-    ResourceSettings resource_settings;
+    viz::ResourceSettings resource_settings;
     resource_settings.texture_id_allocation_chunk_size = 1;
     resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return base::WrapUnique(new FakeResourceProvider(
         context_provider, shared_bitmap_manager, nullptr, nullptr, true, false,
         resource_settings));
@@ -32,10 +32,10 @@
       ContextProvider* context_provider,
       SharedBitmapManager* shared_bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
-    ResourceSettings resource_settings;
+    viz::ResourceSettings resource_settings;
     resource_settings.texture_id_allocation_chunk_size = 1;
     resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return base::WrapUnique(new FakeResourceProvider(
         context_provider, shared_bitmap_manager, gpu_memory_buffer_manager,
         nullptr, true, false, resource_settings));
@@ -48,7 +48,7 @@
                        BlockingTaskRunner* blocking_main_thread_task_runner,
                        bool delegated_sync_points_required,
                        bool enable_color_corect_rasterization,
-                       const ResourceSettings resource_settings)
+                       const viz::ResourceSettings resource_settings)
       : ResourceProvider(context_provider,
                          shared_bitmap_manager,
                          gpu_memory_buffer_manager,
diff --git a/cc/test/layer_test_common.h b/cc/test/layer_test_common.h
index 87466a0..90494d5 100644
--- a/cc/test/layer_test_common.h
+++ b/cc/test/layer_test_common.h
@@ -194,6 +194,9 @@
     scoped_refptr<AnimationTimeline> timeline() { return timeline_; }
     scoped_refptr<AnimationTimeline> timeline_impl() { return timeline_impl_; }
 
+    void BuildPropertyTreesForTesting() {
+      host_impl()->active_tree()->BuildPropertyTreesForTesting();
+    }
     void SetElementIdsForTesting() {
       host_impl()->active_tree()->SetElementIdsForTesting();
     }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index c3b179f..af95a2e 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -19,7 +19,6 @@
 #include "cc/input/input_handler.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/test/animation_test_common.h"
 #include "cc/test/begin_frame_args_test.h"
 #include "cc/test/fake_layer_tree_host_client.h"
@@ -34,6 +33,7 @@
 #include "cc/trees/proxy_impl.h"
 #include "cc/trees/proxy_main.h"
 #include "cc/trees/single_thread_proxy.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gfx/geometry/size_conversions.h"
 
@@ -834,7 +834,7 @@
   // actions and less dependent on timings to make decisions.
   settings_.enable_latency_recovery = false;
   settings_.resource_settings.buffer_to_texture_target_map =
-      DefaultBufferToTextureTargetMapForTesting();
+      viz::DefaultBufferToTextureTargetMapForTesting();
   InitializeSettings(&settings_);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -866,7 +866,7 @@
   // mocked out.
   constexpr double refresh_rate = 200.0;
   renderer_settings.resource_settings.buffer_to_texture_target_map =
-      DefaultBufferToTextureTargetMapForTesting();
+      viz::DefaultBufferToTextureTargetMapForTesting();
   auto layer_tree_frame_sink = CreateLayerTreeFrameSink(
       renderer_settings, refresh_rate, std::move(shared_context_provider),
       std::move(worker_context_provider));
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index b1e7400..4235494 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -1253,15 +1253,16 @@
     }
   }
   image_data->decode.mark_used();
-  DCHECK(uploaded_image);
 
-  if (draw_image.target_color_space().IsValid()) {
+  // TODO(crbug.com/740737): uploaded_image is sometimes null for reasons that
+  // need investigation.
+
+  if (uploaded_image && draw_image.target_color_space().IsValid()) {
     TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage - color conversion");
     uploaded_image = uploaded_image->makeColorSpace(
         draw_image.target_color_space().ToSkColorSpace(),
         SkTransferFunctionBehavior::kIgnore);
   }
-  DCHECK(uploaded_image);
 
   // At-raster may have decoded this while we were unlocked. If so, ignore our
   // result.
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 6497489..c42e166 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -88,7 +88,7 @@
     LayerTreeSettings settings;
     settings.create_low_res_tiling = true;
     settings.resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
 
@@ -2057,7 +2057,7 @@
   LayerTreeSettings CreateSettings() override {
     LayerTreeSettings settings;
     settings.resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
 
@@ -2336,7 +2336,7 @@
     LayerTreeSettings settings;
     settings.enable_checker_imaging = true;
     settings.resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
 
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index bfcad8e..d9faf0c 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -542,13 +542,8 @@
   scroll_layer->SetScrollable(
       gfx::Size(scroll_layer->bounds().width() + kMaxScrollOffset.x(),
                 scroll_layer->bounds().height() + kMaxScrollOffset.y()));
-  SetScrollOffsetDelta(scroll_layer, kScrollDelta);
-  gfx::Transform impl_transform;
+
   scroll_layer->test_properties()->AddChild(std::move(sublayer_scoped_ptr));
-  scroll_layer_scoped_ptr->layer_tree_impl()
-      ->property_trees()
-      ->scroll_tree.UpdateScrollOffsetBaseForTesting(
-          scroll_layer_scoped_ptr->element_id(), kScrollOffset);
 
   std::unique_ptr<LayerImpl> root(
       LayerImpl::Create(host_impl.active_tree(), 3));
@@ -556,6 +551,11 @@
   root->test_properties()->AddChild(std::move(scroll_layer_scoped_ptr));
   LayerImpl* root_layer = root.get();
   host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
+  host_impl.active_tree()->BuildPropertyTreesForTesting();
+  auto& scroll_tree = host_impl.active_tree()->property_trees()->scroll_tree;
+  scroll_tree.UpdateScrollOffsetBaseForTesting(scroll_layer->element_id(),
+                                               kScrollOffset);
+  SetScrollOffsetDelta(scroll_layer, kScrollDelta);
 
   ExecuteCalculateDrawProperties(root_layer, kDeviceScale, page_scale,
                                  scroll_layer->test_properties()->parent,
@@ -5316,7 +5316,6 @@
   clip_parent->SetMasksToBounds(true);
   intervening->SetScrollable(gfx::Size(1, 1));
   intervening->SetElementId(LayerIdToElementIdForTesting(intervening->id()));
-  intervening->SetCurrentScrollOffset(gfx::ScrollOffset(3, 3));
 
   gfx::Transform translation_transform;
   translation_transform.Translate(2, 2);
@@ -5333,6 +5332,8 @@
   render_surface2->test_properties()->force_render_surface = true;
   clip_child->SetPosition(gfx::PointF(-10.f, -10.f));
   clip_child->SetBounds(gfx::Size(60, 60));
+  BuildPropertyTreesForTesting();
+  intervening->SetCurrentScrollOffset(gfx::ScrollOffset(3, 3));
   ExecuteCalculateDrawProperties(root);
 
   EXPECT_TRUE(GetRenderSurface(root));
@@ -6238,6 +6239,7 @@
   AddAnimatedTransformToElementWithPlayer(animated_layer->element_id(),
                                           timeline_impl(), 1.0,
                                           start_operations, end_operations);
+  BuildPropertyTreesForTesting();
   gfx::Vector2dF scroll_delta(5.f, 9.f);
   SetScrollOffsetDelta(scroller, scroll_delta);
 
@@ -8577,7 +8579,6 @@
   frame_clip->SetDrawsContent(true);
   scroller->SetBounds(gfx::Size(1000, 1000));
   scroller->SetElementId(LayerIdToElementIdForTesting(scroller->id()));
-  scroller->SetCurrentScrollOffset(gfx::ScrollOffset(100, 100));
   scroller->SetElementId(LayerIdToElementIdForTesting(scroller->id()));
   scroller->SetScrollable(frame_clip->bounds());
   scroller->SetDrawsContent(true);
@@ -8587,6 +8588,9 @@
   fixed->SetDrawsContent(true);
   fixed->test_properties()->force_render_surface = true;
 
+  BuildPropertyTreesForTesting();
+  scroller->SetCurrentScrollOffset(gfx::ScrollOffset(100, 100));
+
   LayerPositionConstraint constraint;
   constraint.set_is_fixed_position(true);
   fixed->test_properties()->position_constraint = constraint;
@@ -8656,6 +8660,9 @@
   scroll_child->SetBounds(gfx::Size(40, 40));
   scroll_child->SetDrawsContent(true);
   scroll_parent->SetBounds(gfx::Size(30, 30));
+  scroll_parent->SetScrollable(gfx::Size(50, 50));
+  scroll_parent->SetElementId(
+      LayerIdToElementIdForTesting(scroll_parent->id()));
   scroll_parent->SetDrawsContent(true);
 
   scroll_child->test_properties()->scroll_parent = scroll_parent;
@@ -8667,12 +8674,13 @@
   EXPECT_EQ(gfx::Rect(25, 25), scroll_child->visible_layer_rect());
 
   scroll_child->SetPosition(gfx::PointF(0, -10.f));
-  scroll_parent->SetElementId(
-      LayerIdToElementIdForTesting(scroll_parent->id()));
   scroll_parent->SetCurrentScrollOffset(gfx::ScrollOffset(0.f, 10.f));
-  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
   ExecuteCalculateDrawProperties(root);
   EXPECT_EQ(gfx::Rect(0, 5, 25, 25), scroll_child->visible_layer_rect());
+
+  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
+  ExecuteCalculateDrawProperties(root);
+  EXPECT_EQ(gfx::Rect(0, 10, 25, 25), scroll_child->visible_layer_rect());
 }
 
 static void CopyOutputCallback(std::unique_ptr<CopyOutputResult> result) {}
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 850284f..1753e6d 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -132,7 +132,7 @@
     settings.minimum_occlusion_tracking_size = gfx::Size();
     settings.resource_settings.texture_id_allocation_chunk_size = 1;
     settings.resource_settings.buffer_to_texture_target_map =
-        DefaultBufferToTextureTargetMapForTesting();
+        viz::DefaultBufferToTextureTargetMapForTesting();
     return settings;
   }
 
@@ -4763,11 +4763,13 @@
   child->SetDrawsContent(true);
   child->test_properties()->is_container_for_fixed_position_layers = true;
 
-  // scroll child to limit
-  SetScrollOffsetDelta(child.get(), gfx::Vector2dF(0, 100.f));
+  LayerImpl* child_ptr = child.get();
   outer_viewport_scroll_layer->test_properties()->AddChild(std::move(child));
   host_impl_->active_tree()->BuildPropertyTreesForTesting();
 
+  // Scroll child to the limit.
+  SetScrollOffsetDelta(child_ptr, gfx::Vector2dF(0, 100.f));
+
   // Scroll 25px to hide browser controls
   gfx::Vector2dF scroll_delta(0.f, 25.f);
   EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index ee162b3..e90083b 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -156,37 +156,31 @@
   SetScrollbarGeometriesNeedUpdate();
 
   DCHECK(lifecycle().AllowsPropertyTreeAccess());
-  TransformTree& transform_tree = property_trees()->transform_tree;
   ScrollTree& scroll_tree = property_trees()->scroll_tree;
-  int transform_id = TransformTree::kInvalidNodeId;
+  const auto* scroll_node = scroll_tree.FindNodeFromElementId(id);
 
-  // If pending tree topology changed and we still want to notify the pending
-  // tree about scroll offset in the active tree, we may not find the
-  // corresponding pending layer.
-  // TODO(pdr): Remove this use of LayerByElementId and instead look up the
-  // scroll node via ElementId and then set transform_id to the scroll node's
-  // transform node index.
-  if (auto* layer = LayerByElementId(id)) {
-    // TODO(sunxd): when we have a layer_id to property_tree index map in
-    // property trees, use the transform_id parameter instead of looking for
-    // indices from LayerImpls.
-    transform_id = layer->transform_tree_index();
-  } else {
+  // TODO(pdr): There shouldn't be any cases where scroll offset is updated
+  // without a scroll node and we should remove this check entirely.
+  if (!scroll_node) {
     DCHECK(!IsActiveTree());
+
+    // If a scroll node does not yet exist, ensure the property trees are marked
+    // for rebuilding which will update the TransformNode scroll offset.
+    DCHECK(property_trees()->needs_rebuild);
     return;
   }
 
-  if (transform_id != TransformTree::kInvalidNodeId) {
-    TransformNode* node = transform_tree.Node(transform_id);
-    if (node->scroll_offset != scroll_tree.current_scroll_offset(id)) {
-      node->scroll_offset = scroll_tree.current_scroll_offset(id);
-      node->needs_local_transform_update = true;
-      transform_tree.set_needs_update(true);
-    }
-    node->transform_changed = true;
-    property_trees()->changed = true;
-    set_needs_update_draw_properties();
+  DCHECK(scroll_node->transform_id != TransformTree::kInvalidNodeId);
+  TransformTree& transform_tree = property_trees()->transform_tree;
+  auto* transform_node = transform_tree.Node(scroll_node->transform_id);
+  if (transform_node->scroll_offset != scroll_tree.current_scroll_offset(id)) {
+    transform_node->scroll_offset = scroll_tree.current_scroll_offset(id);
+    transform_node->needs_local_transform_update = true;
+    transform_tree.set_needs_update(true);
   }
+  transform_node->transform_changed = true;
+  property_trees()->changed = true;
+  set_needs_update_draw_properties();
 
   if (IsActiveTree() && layer_tree_host_impl_->pending_tree())
     layer_tree_host_impl_->pending_tree()->DidUpdateScrollOffset(id);
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index a154d9b..56743c60 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -14,10 +14,10 @@
 #include "cc/debug/layer_tree_debug_state.h"
 #include "cc/output/managed_memory_policy.h"
 #include "cc/output/renderer_settings.h"
-#include "cc/resources/resource_settings.h"
 #include "cc/scheduler/scheduler_settings.h"
 #include "cc/tiles/tile_manager_settings.h"
 #include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/resources/resource_settings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -32,7 +32,7 @@
   SchedulerSettings ToSchedulerSettings() const;
   TileManagerSettings ToTileManagerSettings() const;
 
-  ResourceSettings resource_settings;
+  viz::ResourceSettings resource_settings;
   bool single_thread_proxy_scheduler = true;
   bool main_frame_before_activation_enabled = false;
   bool using_synchronous_renderer_compositor = false;
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index e65cd75..edba999 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -35,28 +35,28 @@
   PropertyTrees* property_trees;
   LayerType* transform_tree_parent;
   LayerType* transform_fixed_parent;
-  int clip_tree_parent;
-  int effect_tree_parent;
-  int scroll_tree_parent;
-  int closest_ancestor_with_copy_request;
   const LayerType* page_scale_layer;
   const LayerType* inner_viewport_scroll_layer;
   const LayerType* outer_viewport_scroll_layer;
   const LayerType* overscroll_elasticity_layer;
-  gfx::Vector2dF elastic_overscroll;
+  const gfx::Transform* device_transform;
   float page_scale_factor;
+  int clip_tree_parent;
+  int effect_tree_parent;
+  int scroll_tree_parent;
+  int closest_ancestor_with_copy_request;
+  uint32_t main_thread_scrolling_reasons;
+  SkColor safe_opaque_background_color;
   bool in_subtree_of_page_scale_layer;
   bool affected_by_inner_viewport_bounds_delta;
   bool affected_by_outer_viewport_bounds_delta;
   bool should_flatten;
   bool is_hidden;
-  uint32_t main_thread_scrolling_reasons;
   bool scroll_tree_parent_created_by_uninheritable_criteria;
-  const gfx::Transform* device_transform;
-  gfx::Transform compound_transform_since_render_target;
   bool animation_axis_aligned_since_render_target;
   bool not_axis_aligned_since_last_clip;
-  SkColor safe_opaque_background_color;
+  gfx::Transform compound_transform_since_render_target;
+  gfx::Vector2dF elastic_overscroll;
 };
 
 static LayerPositionConstraint PositionConstraint(Layer* layer) {
diff --git a/chrome/OWNERS b/chrome/OWNERS
index e0132b8..fbf4726 100644
--- a/chrome/OWNERS
+++ b/chrome/OWNERS
@@ -12,3 +12,5 @@
 # structural changes, please get a review from a reviewer in this file.
 per-file *.gni=*
 per-file BUILD.gn=file://build/OWNERS
+per-file VERSION=dimu@chromium.com
+per-file VERSION=mmoss@chromium.com
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c59688c1..73b2877 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -861,6 +861,10 @@
   apk_name = "ChromeModernPublic"
   shared_libraries = [ ":chrome" ]
 
+  if (!is_java_debug) {
+    png_to_webp = true
+  }
+
   # Always enable load_library_from_apk.
   load_library_from_apk = chromium_linker_supported
 }
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 9f8ad322..037d16b3 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -143,6 +143,7 @@
         proguard_configs = []
       }
       proguard_configs += [ "//android_webview/apk/java/proguard.flags" ]
+      png_to_webp = true
     }
   }
 }
diff --git a/chrome/android/java/res/layout/password_entry_editor_interactive.xml b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
index 014fe390..f758811 100644
--- a/chrome/android/java/res/layout/password_entry_editor_interactive.xml
+++ b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
@@ -15,48 +15,7 @@
         android:orientation="vertical"
         android:title="@string/password_entry_editor_title">
 
-        <TextView
-            android:text="@string/password_entry_editor_site_title"
-            android:textColor="@color/google_blue_700"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="10dp"
-            android:layout_marginStart="15dp"
-            android:gravity="center_vertical"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-
-            <TextView
-                android:id="@+id/password_entry_editor_url"
-                android:textColor="@color/default_text_color"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="10dp"
-                android:layout_marginStart="15dp"
-                android:textAppearance="?android:attr/textAppearanceMedium" />
-
-            <View
-                android:layout_width="0dp"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <ImageButton
-                android:id="@+id/password_entry_editor_copy_site"
-                android:background="@null"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="end"
-                android:layout_marginTop="10dp"
-                android:layout_marginEnd="15dp"
-                android:src="@drawable/ic_content_copy"
-                android:contentDescription="@string/password_entry_editor_copy_stored_site"
-                style="?android:attr/buttonStyleSmall" />
-
-        </LinearLayout>
+        <include layout="@layout/password_entry_editor_site_row"/>
 
         <TextView
             android:text="@string/password_entry_editor_username_title"
diff --git a/chrome/android/java/res/layout/password_entry_editor_site_row.xml b/chrome/android/java/res/layout/password_entry_editor_site_row.xml
new file mode 100644
index 0000000..cd5a77f
--- /dev/null
+++ b/chrome/android/java/res/layout/password_entry_editor_site_row.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file. -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <TextView
+        android:text="@string/password_entry_editor_site_title"
+        android:textColor="@color/google_blue_700"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:layout_marginStart="15dp"
+        android:gravity="center_vertical"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/password_entry_editor_url"
+            android:textColor="@color/default_text_color"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:layout_marginStart="15dp"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <View
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+        <ImageButton
+            android:id="@+id/password_entry_editor_copy_site"
+            android:background="@null"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end"
+            android:layout_marginTop="10dp"
+            android:layout_marginEnd="15dp"
+            android:src="@drawable/ic_content_copy"
+            android:contentDescription="@string/password_entry_editor_copy_stored_site"
+            style="?android:attr/buttonStyleSmall" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/chrome/android/java/res/layout/password_entry_exception.xml b/chrome/android/java/res/layout/password_entry_exception.xml
new file mode 100644
index 0000000..f71bcdf0
--- /dev/null
+++ b/chrome/android/java/res/layout/password_entry_exception.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true" >
+
+    <LinearLayout
+        android:id="@+id/password_entry_exception"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:title="@string/password_entry_editor_title">
+
+        <include layout="@layout/password_entry_editor_site_row"/>
+    </LinearLayout>
+
+</ScrollView>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 3addc59..6ed5815 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -37,8 +37,8 @@
 
     /**
      * @return Whether the native FeatureList has been initialized. If this method returns false,
-     * none of the methods in this class that require native access should be called (except in
-     * tests if test features have been set).
+     *         none of the methods in this class that require native access should be called (except
+     *         in tests if test features have been set).
      */
     public static boolean isInitialized() {
         if (sTestFeatures != null) return true;
@@ -154,6 +154,7 @@
     public static final String CCT_BACKGROUND_TAB = "CCTBackgroundTab";
     public static final String CCT_EXTERNAL_LINK_HANDLING = "CCTExternalLinkHandling";
     public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI";
+    public static final String CCT_REDIRECT_PRECONNECT = "CCTRedirectPreconnect";
     public static final String CHROME_HOME = "ChromeHome";
     public static final String CHROME_HOME_EXPAND_BUTTON = "ChromeHomeExpandButton";
     public static final String CONSISTENT_OMNIBOX_GEOLOCATION = "ConsistentOmniboxGeolocation";
@@ -199,6 +200,7 @@
     public static final String PAY_WITH_GOOGLE_V1 = "PayWithGoogleV1";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
     public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels";
+    public static final String SPANNABLE_INLINE_AUTOCOMPLETE = "SpannableInlineAutocomplete";
     public static final String TAB_REPARENTING = "TabReparenting";
     public static final String VIDEO_PERSISTENCE = "VideoPersistence";
     public static final String VR_BROWSING_FEEDBACK = "VrBrowsingFeedback";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index c8238ae..5d33232 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -492,8 +492,10 @@
                     && preferenceManager.getPromosSkippedOnFirstStart()) {
                 // Data reduction promo should be temporarily suppressed if the sign in promo is
                 // shown to avoid nagging users too much.
+                TabModel currentModel = mTabModelSelectorImpl.getCurrentModel();
                 if (!SigninPromoUtil.launchSigninPromoIfNeeded(this)) {
-                    if (!DataReductionPromoScreen.launchDataReductionPromo(this)
+                    if (!DataReductionPromoScreen.launchDataReductionPromo(
+                                this, currentModel.isIncognito())
                             && getBottomSheet() != null) {
                         getBottomSheet().showHelpBubbleIfNecessary();
                     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index 7c6ccb38..5dbfe443 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -6,6 +6,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -227,24 +228,29 @@
      */
     public void maybePreconnectUrlAndSubResources(Profile profile, String url) {
         ThreadUtils.assertOnUiThread();
-        if (!DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()) {
-            // If there is already a DNS request in flight for this URL, then
-            // the preconnection will start by issuing a DNS request for the
-            // same domain, as the result is not cached. However, such a DNS
-            // request has already been sent from this class, so it is better to
-            // wait for the answer to come back before preconnecting. Otherwise,
-            // the preconnection logic will wait for the result of the second
-            // DNS request, which should arrive after the result of the first
-            // one. Note that we however need to wait for the main thread to be
-            // available in this case, since the preconnection will be sent from
-            // AsyncTask.onPostExecute(), which may delay it.
-            if (mDnsRequestsInFlight.contains(url)) {
-                // Note that if two requests come for the same URL with two
-                // different profiles, the last one will win.
-                mPendingPreconnectWithProfile.put(url, profile);
-            } else {
-                nativePreconnectUrlAndSubresources(profile, url);
-            }
+
+        Uri uri = Uri.parse(url);
+        if (uri == null) return;
+        // HTTP connections will not be used when the data reduction proxy is enabled.
+        if (DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()
+                && UrlConstants.HTTP_SCHEME.equals(uri.normalizeScheme().getScheme())) {
+            return;
+        }
+
+        // If there is already a DNS request in flight for this URL, then the preconnection will
+        // start by issuing a DNS request for the same domain, as the result is not cached. However,
+        // such a DNS request has already been sent from this class, so it is better to wait for the
+        // answer to come back before preconnecting. Otherwise, the preconnection logic will wait
+        // for the result of the second DNS request, which should arrive after the result of the
+        // first one. Note that we however need to wait for the main thread to be available in this
+        // case, since the preconnection will be sent from AsyncTask.onPostExecute(), which may
+        // delay it.
+        if (mDnsRequestsInFlight.contains(url)) {
+            // Note that if two requests come for the same URL with two different profiles, the last
+            // one will win.
+            mPendingPreconnectWithProfile.put(url, profile);
+        } else {
+            nativePreconnectUrlAndSubresources(profile, url);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 8b47612..47b25c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -13,6 +13,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
 import android.support.annotation.IdRes;
 import android.support.annotation.Nullable;
 import android.view.Gravity;
@@ -26,6 +27,7 @@
 import android.view.View.OnKeyListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
+import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ImageButton;
@@ -163,6 +165,11 @@
         mPopup.setFocusable(true);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
 
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            // The window layout type affects the z-index of the popup window on M+.
+            mPopup.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+        }
+
         boolean anchorAtBottom = isAnchorAtBottom(anchorView, visibleDisplayFrame);
         int footerHeight = 0;
         mPopup.setOnDismissListener(new OnDismissListener() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 1e44667..3d84d48 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -71,10 +71,11 @@
          * Called when the subkeys are received sucessfully.
          * Here the subkeys are admin areas.
          *
-         * @param subKeys The subKeys.
+         * @param subKeysCodes The subkeys' codes.
+         * @param subKeysNames The subkeys' names.
          */
         @CalledByNative("GetSubKeysRequestDelegate")
-        void onSubKeysReceived(String[] subKeys);
+        void onSubKeysReceived(String[] subKeysCodes, String[] subKeysNames);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
index 1487e1f..d5038af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/ClientManager.java
@@ -493,6 +493,20 @@
                               : params.mSpeculationMode;
     }
 
+    /**
+     * Returns whether an origin is first-party with respect to a session, that is if the
+     * application linked to the session has a relation with the provided origin. This does not
+     * calls OriginVerifier, but only checks the cached relations.
+     *
+     * @param session The session.
+     * @param origin Origin to verify
+     */
+    public synchronized boolean isFirstPartyOriginForSession(
+            CustomTabsSessionToken session, Uri origin) {
+        SessionParams params = mSessionParams.get(session);
+        return params == null ? false : OriginVerifier.isValidOrigin(params.packageName, origin);
+    }
+
     /** Tries to bind to a client to keep it alive, and returns true for success. */
     public synchronized boolean keepAliveForSession(CustomTabsSessionToken session, Intent intent) {
         // When an application is bound to a service, its priority is raised to
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 7d83ded..23e12bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.customtabs;
 
 import android.app.Activity;
+import android.app.Application;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -237,6 +238,9 @@
 
         String url = IntentHandler.getUrlFromIntent(intent);
         if (TextUtils.isEmpty(url)) return false;
+        CustomTabsConnection connection = CustomTabsConnection.getInstance(
+                (Application) ContextUtils.getApplicationContext());
+        connection.onHandledIntent(session, url, intent);
         sActiveContentHandler.loadUrlAndTrackFromTimestamp(new LoadUrlParams(url),
                 IntentHandler.getTimestampFromIntent(intent));
         return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 8ca1690..e79e1d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -28,6 +28,7 @@
 import android.widget.RemoteViews;
 
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TimeUtils;
@@ -56,6 +57,7 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.Referrer;
+import org.chromium.net.GURLUtils;
 
 import java.io.BufferedReader;
 import java.io.FileReader;
@@ -116,6 +118,10 @@
     @VisibleForTesting
     static final int HIDDEN_TAB = 3;
 
+    // TODO(lizeb): Move to the support library.
+    @VisibleForTesting
+    static final String REDIRECT_ENDPOINT_KEY = "android.support.customtabs.REDIRECT_ENDPOINT";
+
     private static AtomicReference<CustomTabsConnection> sInstance = new AtomicReference<>();
 
     /** Holds the parameters for the current speculation. */
@@ -346,15 +352,15 @@
         return true;
     }
 
-    /** @return the URL converted to string, or null if it's invalid. */
-    private static String checkAndConvertUri(Uri uri) {
-        if (uri == null) return null;
+    /** @return the URL or null if it's invalid. */
+    private boolean isValid(Uri uri) {
+        if (uri == null) return false;
         // Don't do anything for unknown schemes. Not having a scheme is allowed, as we allow
         // "www.example.com".
         String scheme = uri.normalizeScheme().getScheme();
         boolean allowedScheme = scheme == null || scheme.equals("http") || scheme.equals("https");
-        if (!allowedScheme) return null;
-        return uri.toString();
+        if (!allowedScheme) return false;
+        return true;
     }
 
     /**
@@ -397,7 +403,7 @@
         boolean atLeastOneUrl = false;
         if (likelyBundles == null) return false;
         WarmupManager warmupManager = WarmupManager.getInstance();
-        Profile profile = Profile.getLastUsedProfile();
+        Profile profile = Profile.getLastUsedProfile().getOriginalProfile();
         for (Bundle bundle : likelyBundles) {
             Uri uri;
             try {
@@ -405,9 +411,8 @@
             } catch (ClassCastException e) {
                 continue;
             }
-            String url = checkAndConvertUri(uri);
-            if (url != null) {
-                warmupManager.maybePreconnectUrlAndSubResources(profile, url);
+            if (isValid(uri)) {
+                warmupManager.maybePreconnectUrlAndSubResources(profile, uri.toString());
                 atLeastOneUrl = true;
             }
         }
@@ -430,7 +435,7 @@
             final Bundle extras, final List<Bundle> otherLikelyBundles) {
         final boolean lowConfidence =
                 (url == null || TextUtils.isEmpty(url.toString())) && otherLikelyBundles != null;
-        final String urlString = checkAndConvertUri(url);
+        final String urlString = isValid(url) ? url.toString() : null;
         if (url != null && urlString == null && !lowConfidence) return false;
 
         // Things below need the browser process to be initialized.
@@ -725,6 +730,35 @@
         return null;
     }
 
+    /**
+     * Called when an intent is handled by either an existing or a new CustomTabActivity.
+     *
+     * @param session Session extracted from the intent.
+     * @param url URL extracted from the intent.
+     * @param intent incoming intent.
+     */
+    void onHandledIntent(CustomTabsSessionToken session, String url, Intent intent) {
+        // For the preconnection to not be a no-op, we need more than just the native library.
+        Context context = ContextUtils.getApplicationContext();
+        if (!ChromeBrowserInitializer.getInstance(context).hasNativeInitializationCompleted()) {
+            return;
+        }
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_REDIRECT_PRECONNECT)) return;
+
+        // Conditions:
+        // - There is a valid redirect endpoint.
+        // - The URL's origin is first party with respect to the app.
+        Uri redirectEndpoint = intent.getParcelableExtra(REDIRECT_ENDPOINT_KEY);
+        if (redirectEndpoint == null || !isValid(redirectEndpoint)) return;
+
+        String origin = GURLUtils.getOrigin(url);
+        if (origin == null) return;
+        if (!mClientManager.isFirstPartyOriginForSession(session, Uri.parse(origin))) return;
+
+        WarmupManager.getInstance().maybePreconnectUrlAndSubResources(
+                Profile.getLastUsedProfile(), redirectEndpoint.toString());
+    }
+
     /** See {@link ClientManager#getReferrerForSession(CustomTabsSessionToken)} */
     public Referrer getReferrerForSession(CustomTabsSessionToken session) {
         return mClientManager.getReferrerForSession(session);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
index b7c6ba4..9754d33 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/OriginVerifier.java
@@ -30,8 +30,10 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Used to verify postMessage origin for a designated package name.
@@ -47,21 +49,25 @@
 class OriginVerifier {
     private static final String TAG = "OriginVerifier";
     private static final char[] HEX_CHAR_LOOKUP = "0123456789ABCDEF".toCharArray();
-    private static Map<String, Uri> sCachedOriginMap;
+    private static Map<String, Set<Uri>> sPackageToCachedOrigins;
     private final OriginVerificationListener mListener;
     private final String mPackageName;
     private final String mSignatureFingerprint;
     private long mNativeOriginVerifier = 0;
     private Uri mOrigin;
 
-    /**
-     * To be used for prepopulating verified origin for testing functionality.
-     * @param packageName The package name to prepopulate for.
-     * @param origin The origin to add as verified.
-     */
-    @VisibleForTesting
-    static void prePopulateVerifiedOriginForTesting(String packageName, Uri origin) {
-        cacheVerifiedOriginIfNeeded(packageName, origin);
+    /** Small helper class to post a result of origin verification. */
+    private class VerifiedCallback implements Runnable {
+        private final boolean mResult;
+
+        public VerifiedCallback(boolean result) {
+            this.mResult = result;
+        }
+
+        @Override
+        public void run() {
+            originVerified(mResult);
+        }
     }
 
     private static Uri getPostMessageOriginFromVerifiedOrigin(
@@ -70,11 +76,44 @@
                 + verifiedOrigin.getHost() + "/" + packageName);
     }
 
-    private static void cacheVerifiedOriginIfNeeded(String packageName, Uri origin) {
-        if (sCachedOriginMap == null) sCachedOriginMap = new HashMap<>();
-        if (!sCachedOriginMap.containsKey(packageName)) {
-            sCachedOriginMap.put(packageName, origin);
+    /** Clears all known relations. */
+    @VisibleForTesting
+    static void reset() {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins != null) sPackageToCachedOrigins.clear();
+    }
+
+    /**
+     * Mark an origin as verified for a package.
+     * @param packageName The package name to prepopulate for.
+     * @param origin The origin to add as verified.
+     */
+    static void addVerifiedOriginForPackage(String packageName, Uri origin) {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins == null) sPackageToCachedOrigins = new HashMap<>();
+        Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName);
+        if (cachedOrigins == null) {
+            cachedOrigins = new HashSet<Uri>();
+            sPackageToCachedOrigins.put(packageName, cachedOrigins);
         }
+        cachedOrigins.add(origin);
+    }
+
+    /**
+     * Returns whether an origin is first-party relative to a given package name.
+     *
+     * This only returns data from previously cached relations, and does not
+     * trigger an asynchronous validation.
+     *
+     * @param packageName The package name
+     * @param origin The origin to verify
+     */
+    static boolean isValidOrigin(String packageName, Uri origin) {
+        ThreadUtils.assertOnUiThread();
+        if (sPackageToCachedOrigins == null) return false;
+        Set<Uri> cachedOrigins = sPackageToCachedOrigins.get(packageName);
+        if (cachedOrigins == null) return false;
+        return cachedOrigins.contains(origin);
     }
 
     /**
@@ -112,24 +151,13 @@
         ThreadUtils.assertOnUiThread();
         mOrigin = origin;
         if (!UrlConstants.HTTPS_SCHEME.equals(mOrigin.getScheme().toLowerCase(Locale.US))) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(false);
-                }
-            });
+            ThreadUtils.runOnUiThread(new VerifiedCallback(false));
             return;
         }
 
         // If this origin is cached as verified already, use that.
-        Uri cachedOrigin = getCachedOriginIfExists();
-        if (cachedOrigin != null && cachedOrigin.equals(origin)) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(true);
-                }
-            });
+        if (isValidOrigin(mPackageName, origin)) {
+            ThreadUtils.runOnUiThread(new VerifiedCallback(true));
             return;
         }
         if (mNativeOriginVerifier != 0) cleanUp();
@@ -142,14 +170,7 @@
         assert mNativeOriginVerifier != 0;
         boolean success = nativeVerifyOrigin(
                 mNativeOriginVerifier, mPackageName, mSignatureFingerprint, mOrigin.toString());
-        if (!success) {
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    originVerified(false);
-                }
-            });
-        }
+        if (!success) ThreadUtils.runOnUiThread(new VerifiedCallback(false));
     }
 
     /**
@@ -219,18 +240,13 @@
     @CalledByNative
     private void originVerified(boolean originVerified) {
         if (originVerified) {
-            cacheVerifiedOriginIfNeeded(mPackageName, mOrigin);
+            addVerifiedOriginForPackage(mPackageName, mOrigin);
             mOrigin = getPostMessageOriginFromVerifiedOrigin(mPackageName, mOrigin);
         }
         mListener.onOriginVerified(mPackageName, mOrigin, originVerified);
         cleanUp();
     }
 
-    private Uri getCachedOriginIfExists() {
-        if (sCachedOriginMap == null) return null;
-        return sCachedOriginMap.get(mPackageName);
-    }
-
     private native long nativeInit(Profile profile);
     private native boolean nativeVerifyOrigin(long nativeOriginVerifier, String packageName,
             String signatureFingerprint, String origin);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 3238705..dbb3204 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -113,6 +113,13 @@
     }
 
     /**
+     * @return whether native initialization is complete.
+     */
+    public boolean hasNativeInitializationCompleted() {
+        return mNativeInitializationComplete;
+    }
+
+    /**
      * Initializes the Chrome browser process synchronously.
      *
      * @throws ProcessInitException if there is a problem with the native library.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 2cc2d10..4f61348 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -280,11 +280,13 @@
 
         mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * getMaxTileColumns());
 
+        mRecyclerView.init(mUiConfig, mContextMenuManager);
+
         // Set up snippets
         NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout,
                 mUiConfig, offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null);
         newTabPageAdapter.refreshSuggestions();
-        mRecyclerView.init(mUiConfig, mContextMenuManager, newTabPageAdapter);
+        mRecyclerView.setAdapter(newTabPageAdapter);
         mRecyclerView.getLinearLayoutManager().scrollToPosition(scrollPosition);
 
         setupScrollHandling();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 0eab84b..1bc12d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -256,7 +256,7 @@
 
         // We are assuming for now that the adapter is used with a single RecyclerView.
         // Getting the reference as we are doing here is going to be broken if that changes.
-        assert mRecyclerView == null;
+        assert mRecyclerView == null || recyclerView == mRecyclerView;
 
         // FindBugs chokes on the cast below when not checked, raising BC_UNCONFIRMED_CAST
         assert recyclerView instanceof SuggestionsRecyclerView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
index 1edaf88d..3cb7a7c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.StrictMode;
+import android.support.annotation.CallSuper;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -20,6 +21,7 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.widget.VerticallyFixedEditText;
 
 /**
@@ -52,18 +54,25 @@
     }
 
     private void ensureModel() {
-        if (mModel == null) {
+        if (mModel != null) return;
+
+        if (ChromeFeatureList.isInitialized()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            Log.i(TAG, "Using spannable model...");
+            mModel = new SpannableAutocompleteEditTextModel(this);
+        } else {
+            Log.i(TAG, "Using non-spannable model...");
             mModel = new AutocompleteEditTextModel(this);
-            // Feed initial values.
-            mModel.setIgnoreTextChangeFromAutocomplete(true);
-            mModel.onFocusChanged(hasFocus());
-            mModel.onSetText(getText());
-            mModel.onTextChanged(getText(), 0, 0, getText().length());
-            mModel.onSelectionChanged(getSelectionStart(), getSelectionEnd());
-            if (mLastEditWasPaste) mModel.onPaste();
-            mModel.setIgnoreTextChangeFromAutocomplete(false);
-            mModel.setIgnoreTextChangeFromAutocomplete(mIgnoreTextChangesForAutocomplete);
         }
+        // Feed initial values.
+        mModel.setIgnoreTextChangeFromAutocomplete(true);
+        mModel.onFocusChanged(hasFocus());
+        mModel.onSetText(getText());
+        mModel.onTextChanged(getText(), 0, 0, getText().length());
+        mModel.onSelectionChanged(getSelectionStart(), getSelectionEnd());
+        if (mLastEditWasPaste) mModel.onPaste();
+        mModel.setIgnoreTextChangeFromAutocomplete(false);
+        mModel.setIgnoreTextChangeFromAutocomplete(mIgnoreTextChangesForAutocomplete);
     }
 
     /**
@@ -142,6 +151,7 @@
     }
 
     /** Call this when text is pasted. */
+    @CallSuper
     public void onPaste() {
         mLastEditWasPaste = true;
         if (mModel != null) mModel.onPaste();
@@ -233,16 +243,13 @@
 
     @Override
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        return createInputConnection(super.onCreateInputConnection(outAttrs));
-    }
-
-    @VisibleForTesting
-    public InputConnection createInputConnection(InputConnection target) {
+        InputConnection target = super.onCreateInputConnection(outAttrs);
         // Initially, target is null until View gets the focus.
         if (target == null && mModel == null) {
-            if (DEBUG) Log.i(TAG, "createInputConnection - ignoring null target.");
+            if (DEBUG) Log.i(TAG, "onCreateInputConnection - ignoring null target.");
             return null;
         }
+        if (DEBUG) Log.i(TAG, "onCreateInputConnection: " + target);
         ensureModel();
         InputConnection retVal = mModel.onCreateInputConnection(target);
         if (mIgnoreImeForTest) return null;
@@ -250,8 +257,14 @@
     }
 
     @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
+    public boolean dispatchKeyEvent(final KeyEvent event) {
         if (mIgnoreImeForTest) return true;
+        if (mModel == null) return super.dispatchKeyEvent(event);
+        return mModel.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean super_dispatchKeyEvent(KeyEvent event) {
         return super.dispatchKeyEvent(event);
     }
 
@@ -288,4 +301,7 @@
             sendAccessibilityEventUnchecked(event);
         }
     }
+
+    @Override
+    public void onUpdateSelectionForTesting(int selStart, int selEnd) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
index 2c669ac..8819905 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java
@@ -8,6 +8,7 @@
 import android.text.Selection;
 import android.text.Spanned;
 import android.text.TextUtils;
+import android.view.KeyEvent;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionWrapper;
@@ -18,7 +19,7 @@
  * An autocomplete model that appends autocomplete text at the end of query/URL text and selects it.
  */
 public class AutocompleteEditTextModel implements AutocompleteEditTextModelBase {
-    private static final String TAG = "cr_AutocompleteEdit";
+    private static final String TAG = "cr_AutocompleteModel";
 
     private static final boolean DEBUG = false;
 
@@ -37,6 +38,10 @@
     private boolean mLastEditWasDelete;
     private boolean mLastEditWasPaste;
 
+    // For testing.
+    private int mLastUpdateSelStart;
+    private int mLastUpdateSelEnd;
+
     public AutocompleteEditTextModel(AutocompleteEditTextModel.Delegate delegate) {
         if (DEBUG) Log.i(TAG, "constructor");
         mDelegate = delegate;
@@ -124,6 +129,7 @@
         mTextDeletedInBatchMode = false;
         mBeforeBatchEditAutocompleteIndex = -1;
         mBeforeBatchEditFullText = null;
+        updateSelectionForTesting();
     }
 
     @Override
@@ -135,6 +141,7 @@
                 boolean textDeleted = mDelegate.getText().length() < beforeTextLength;
                 notifyAutocompleteTextStateChanged(textDeleted, false);
             }
+            updateSelectionForTesting();
         } else {
             mSelectionChangedInBatchMode = true;
         }
@@ -412,6 +419,8 @@
     @Override
     public InputConnection onCreateInputConnection(InputConnection superInputConnection) {
         if (DEBUG) Log.i(TAG, "onCreateInputConnection");
+        mLastUpdateSelStart = mDelegate.getSelectionStart();
+        mLastUpdateSelEnd = mDelegate.getSelectionEnd();
         mInputConnection.setTarget(superInputConnection);
         return mInputConnection;
     }
@@ -465,4 +474,19 @@
             mUserText = null;
         }
     }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mDelegate.super_dispatchKeyEvent(event);
+    }
+
+    private void updateSelectionForTesting() {
+        int selStart = mDelegate.getSelectionStart();
+        int selEnd = mDelegate.getSelectionEnd();
+        if (selStart == mLastUpdateSelStart && selEnd == mLastUpdateSelEnd) return;
+
+        mLastUpdateSelStart = selStart;
+        mLastUpdateSelEnd = selEnd;
+        mDelegate.onUpdateSelectionForTesting(selStart, selEnd);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
index 3e2ed62..6a0cd34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.omnibox;
 
 import android.text.Editable;
+import android.view.KeyEvent;
 import android.view.inputmethod.InputConnection;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -33,6 +34,15 @@
         void setSelection(int autocompleteIndex, int length);
         /** @see TextView#announceForAccessibility(CharSequence) */
         void announceForAccessibility(CharSequence inlineAutocompleteText);
+        /** @see TextView#getHighlightColor() */
+        int getHighlightColor();
+
+        /**
+         * Call super.dispatchKeyEvent(KeyEvent).
+         * @param event Key event.
+         * @return The return value of super.dispatchKeyEvent(KeyEvent).
+         */
+        boolean super_dispatchKeyEvent(KeyEvent event);
 
         /**
          * This is called when autocomplete replaces the whole text.
@@ -51,6 +61,15 @@
          * @param updateDisplay True if string is changed.
          */
         void onAutocompleteTextStateChanged(boolean updateDisplay);
+
+        /**
+         * This is called roughly the same time as when we call
+         * InputMethodManager#updateSelection().
+         *
+         * @param selStart Selection start.
+         * @param selEnd Selection end.
+         */
+        void onUpdateSelectionForTesting(int selStart, int selEnd);
     }
 
     /**
@@ -61,6 +80,13 @@
     InputConnection onCreateInputConnection(InputConnection inputConnection);
 
     /**
+     * Called when View#dispatchKeyEvent(KeyEvent event) is called.
+     * @param event The key event.
+     * @return True if key event has been handled, false otherwise.
+     */
+    boolean dispatchKeyEvent(KeyEvent event);
+
+    /**
      * Called when TextView#setText(CharSequence, BufferType) is called.
      * @param text The new text.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteState.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteState.java
new file mode 100644
index 0000000..97dfd00
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteState.java
@@ -0,0 +1,170 @@
+// 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.omnibox;
+
+import android.text.TextUtils;
+
+import org.chromium.base.VisibleForTesting;
+
+import java.util.Locale;
+
+/**
+ * A state to keep track of EditText and autocomplete.
+ */
+class AutocompleteState {
+    private String mUserText;
+    private String mAutocompleteText;
+    private int mSelStart;
+    private int mSelEnd;
+
+    public AutocompleteState(AutocompleteState a) {
+        copyFrom(a);
+    }
+
+    public AutocompleteState(String userText, String autocompleteText, int selStart, int selEnd) {
+        set(userText, autocompleteText, selStart, selEnd);
+    }
+
+    public void set(String userText, String autocompleteText, int selStart, int selEnd) {
+        mUserText = userText;
+        mAutocompleteText = autocompleteText;
+        mSelStart = selStart;
+        mSelEnd = selEnd;
+    }
+
+    public void copyFrom(AutocompleteState a) {
+        set(a.mUserText, a.mAutocompleteText, a.mSelStart, a.mSelEnd);
+    }
+
+    public String getUserText() {
+        return mUserText;
+    }
+
+    public String getAutocompleteText() {
+        return mAutocompleteText;
+    }
+
+    public boolean hasAutocompleteText() {
+        return !TextUtils.isEmpty(mAutocompleteText);
+    }
+
+    /** @return The whole text including autocomplete text. */
+    public String getText() {
+        return mUserText + mAutocompleteText;
+    }
+
+    public int getSelStart() {
+        return mSelStart;
+    }
+
+    public int getSelEnd() {
+        return mSelEnd;
+    }
+
+    public void setSelection(int selStart, int selEnd) {
+        mSelStart = selStart;
+        mSelEnd = selEnd;
+    }
+
+    public void setUserText(String userText) {
+        mUserText = userText;
+    }
+
+    public void setAutocompleteText(String autocompleteText) {
+        mAutocompleteText = autocompleteText;
+    }
+
+    public void clearAutocompleteText() {
+        mAutocompleteText = "";
+    }
+
+    public boolean isCursorAtEndOfUserText() {
+        return mSelStart == mUserText.length() && mSelEnd == mUserText.length();
+    }
+
+    public boolean isWholeUserTextSelected() {
+        return mSelStart == 0 && mSelEnd == mUserText.length();
+    }
+
+    /**
+     * @param prevState The previous state to compare the current state with.
+     * @return Whether the current state is backward-deleted from prevState.
+     */
+    public boolean isBackwardDeletedFrom(AutocompleteState prevState) {
+        return isCursorAtEndOfUserText() && prevState.isCursorAtEndOfUserText()
+                && isPrefix(mUserText, prevState.mUserText);
+    }
+
+    /**
+     * @param prevState The previous state to compare the current state with.
+     * @return Whether the current state is forward-typed from prevState.
+     */
+    public boolean isForwardTypedFrom(AutocompleteState prevState) {
+        return isCursorAtEndOfUserText() && prevState.isCursorAtEndOfUserText()
+                && isPrefix(prevState.mUserText, mUserText);
+    }
+
+    /**
+     * @param prevState The previous state to compare the current state with.
+     * @return The differential string that has been backward deleted.
+     */
+    public String getBackwardDeletedTextFrom(AutocompleteState prevState) {
+        if (!isBackwardDeletedFrom(prevState)) return null;
+        return prevState.mUserText.substring(mUserText.length());
+    }
+
+    @VisibleForTesting
+    public static boolean isPrefix(String a, String b) {
+        return b.startsWith(a) && b.length() > a.length();
+    }
+
+    /**
+     * When the user manually types the next character that was already suggested in the previous
+     * autocomplete, then the suggestion is still valid if we simply remove one character from the
+     * beginning of it. For example, if prev = "a[bc]" and current text is "ab", this method
+     * constructs "ab[c]".
+     * @param prevState The previous state.
+     * @return Whether the shifting was successful.
+     */
+    public boolean reuseAutocompleteTextIfPrefixExtension(AutocompleteState prevState) {
+        // Shift when user text has grown or remains the same, but still prefix of prevState's whole
+        // text.
+        int diff = mUserText.length() - prevState.mUserText.length();
+        if (diff < 0) return false;
+        if (!isPrefix(mUserText, prevState.getText())) return false;
+        mAutocompleteText = prevState.mAutocompleteText.substring(diff);
+        return true;
+    }
+
+    public void commitAutocompleteText() {
+        mUserText += mAutocompleteText;
+        mAutocompleteText = "";
+    }
+
+    public boolean equalsExceptAutocompleteText(AutocompleteState a) {
+        return mUserText.equals(a.mUserText) && mSelStart == a.mSelStart && mSelEnd == a.mSelEnd;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof AutocompleteState)) return false;
+        if (o == this) return true;
+        AutocompleteState a = (AutocompleteState) o;
+        return mUserText.equals(a.mUserText) && mAutocompleteText.equals(a.mAutocompleteText)
+                && mSelStart == a.mSelStart && mSelEnd == a.mSelEnd;
+    }
+
+    @Override
+    public int hashCode() {
+        return mUserText.hashCode() * 2 + mAutocompleteText.hashCode() * 3 + mSelStart * 5
+                + mSelEnd * 7;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US, "AutocompleteState {[%s][%s] [%d-%d]}", mUserText,
+                mAutocompleteText, mSelStart, mSelEnd);
+    }
+}
\ 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 b1becb8..55260279 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
@@ -858,7 +858,7 @@
         }
         mDeferredNativeRunnables.clear();
 
-        mUrlBar.onOmniboxFullyFunctional();
+        mUrlBar.onNativeLibraryReady();
         updateVisualsForState();
     }
 
@@ -1630,7 +1630,11 @@
                 stopAutocomplete(false);
                 mUrlBar.setUrl(suggestion.getFillIntoEdit(), null);
                 mUrlBar.setSelection(mUrlBar.getText().length());
-                RecordUserAction.record("MobileOmniboxRefineSuggestion");
+                if (suggestion.isUrlSuggestion()) {
+                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Url");
+                } else {
+                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Search");
+                }
             }
 
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
new file mode 100644
index 0000000..2c0ee6f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java
@@ -0,0 +1,565 @@
+// 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.omnibox;
+
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.BackgroundColorSpan;
+import android.view.KeyEvent;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+/**
+ * An autocomplete model that appends autocomplete text at the end of query/URL text as
+ * SpannableString. By wrapping all the keyboard related operations in a batch edit, we can
+ * effectively hide the existence of autocomplete text from keyboard.
+ */
+public class SpannableAutocompleteEditTextModel implements AutocompleteEditTextModelBase {
+    private static final String TAG = "cr_SpanAutocomplete";
+
+    private static final boolean DEBUG = false;
+
+    // A pattern that matches strings consisting of English and European character sets, numbers,
+    // punctuations, and a white space.
+    private static final Pattern NON_COMPOSITIONAL_TEXT_PATTERN = Pattern.compile(
+            "[\\p{script=latin}\\p{script=cyrillic}\\p{script=greek}\\p{script=hebrew}\\p{Punct} "
+            + "0-9]*");
+
+    private final AutocompleteEditTextModelBase.Delegate mDelegate;
+
+    // The current state that reflects EditText view's current state through callbacks such as
+    // onSelectionChanged() and onTextChanged(). It reflects all the latest changes even in a batch
+    // edit. The autocomplete text here is meaningless in the middle of a change.
+    private final AutocompleteState mCurrentState;
+
+    // This keeps track of the state in which previous notification was sent. It prevents redundant
+    // or unnecessary notification.
+    private final AutocompleteState mPreviouslyNotifiedState;
+
+    // This keeps track of the autocompletetext that we need to show (at the end of batch edit if
+    // we are in the middle of it), and also the matching user text that it should be appended to.
+    // Note that this potentially allows the controller to update in a delayed manner.
+    private final AutocompleteState mPreviouslySetState;
+
+    private final SpanController mSpanController;
+
+    private AutocompleteInputConnection mInputConnection;
+    private boolean mLastEditWasTyping = true;
+    private boolean mIgnoreTextChangeFromAutocomplete = true;
+    private int mBatchEditNestCount;
+
+    // For testing.
+    private int mLastUpdateSelStart;
+    private int mLastUpdateSelEnd;
+
+    public SpannableAutocompleteEditTextModel(AutocompleteEditTextModelBase.Delegate delegate) {
+        if (DEBUG) Log.i(TAG, "constructor");
+        mDelegate = delegate;
+        mCurrentState = new AutocompleteState(delegate.getText().toString(), "",
+                delegate.getSelectionStart(), delegate.getSelectionEnd());
+        mPreviouslyNotifiedState = new AutocompleteState(mCurrentState);
+        mPreviouslySetState = new AutocompleteState(mCurrentState);
+
+        mSpanController = new SpanController(delegate);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(InputConnection inputConnection) {
+        mLastUpdateSelStart = mDelegate.getSelectionStart();
+        mLastUpdateSelEnd = mDelegate.getSelectionEnd();
+        if (inputConnection == null) {
+            if (DEBUG) Log.i(TAG, "onCreateInputConnection: null");
+            mInputConnection = null;
+            return null;
+        }
+        if (DEBUG) Log.i(TAG, "onCreateInputConnection");
+        mInputConnection = new AutocompleteInputConnection();
+        mInputConnection.setTarget(inputConnection);
+        return mInputConnection;
+    }
+
+    /**
+     * @param editable The editable.
+     * @return Debug string for the given {@Editable}.
+     */
+    private static String getEditableDebugString(Editable editable) {
+        return String.format(Locale.US, "Editable {[%s] SEL[%d %d] COM[%d %d]}",
+                editable.toString(), Selection.getSelectionStart(editable),
+                Selection.getSelectionEnd(editable),
+                BaseInputConnection.getComposingSpanStart(editable),
+                BaseInputConnection.getComposingSpanEnd(editable));
+    }
+
+    private void notifyAutocompleteTextStateChanged() {
+        if (DEBUG) {
+            Log.i(TAG, "notifyAutocompleteTextStateChanged PRV[%s] CUR[%s] IGN[%b]",
+                    mPreviouslyNotifiedState, mCurrentState, mIgnoreTextChangeFromAutocomplete);
+        }
+        if (mBatchEditNestCount > 0) return;
+        if (mCurrentState.equals(mPreviouslyNotifiedState)) return;
+        // Nothing has changed except that autocomplete text has been set or modified.
+        if (mCurrentState.equalsExceptAutocompleteText(mPreviouslyNotifiedState)
+                && mCurrentState.hasAutocompleteText()) {
+            // Autocomplete text is set by the controller, we should not notify the controller with
+            // the same information.
+            mPreviouslyNotifiedState.copyFrom(mCurrentState);
+            return;
+        }
+        mPreviouslyNotifiedState.copyFrom(mCurrentState);
+        if (mIgnoreTextChangeFromAutocomplete) return;
+        // The current model's mechanism always moves the cursor at the end of user text, so we
+        // don't need to update the display.
+        mDelegate.onAutocompleteTextStateChanged(false /* updateDisplay */);
+    }
+
+    private void clearAutocompleteText() {
+        if (DEBUG) Log.i(TAG, "clearAutocomplete");
+        mPreviouslySetState.clearAutocompleteText();
+        if (!mCurrentState.hasAutocompleteText()) {
+            notifyAutocompleteTextStateChanged();
+            return;
+        }
+        mCurrentState.clearAutocompleteText();
+        // Take effect and notify if not already in a batch edit.
+        if (mInputConnection != null) {
+            mInputConnection.beginBatchEdit();
+            mInputConnection.endBatchEdit();
+        } else {
+            mSpanController.removeSpan();
+            notifyAutocompleteTextStateChanged();
+        }
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(final KeyEvent event) {
+        if (DEBUG) Log.i(TAG, "dispatchKeyEvent");
+        if (mInputConnection == null) {
+            return mDelegate.super_dispatchKeyEvent(event);
+        }
+        mInputConnection.beginBatchEdit();
+        if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
+                && event.getAction() == KeyEvent.ACTION_DOWN) {
+            mInputConnection.commitAutocomplete();
+        }
+        boolean retVal = mDelegate.super_dispatchKeyEvent(event);
+        mInputConnection.endBatchEdit();
+        return retVal;
+    }
+
+    @Override
+    public void onSetText(CharSequence text) {
+        if (DEBUG) Log.i(TAG, "onSetText: " + text);
+    }
+
+    @Override
+    public void onSelectionChanged(int selStart, int selEnd) {
+        if (DEBUG) Log.i(TAG, "onSelectionChanged [%d,%d]", selStart, selEnd);
+        mCurrentState.setSelection(selStart, selEnd);
+        if (mBatchEditNestCount > 0) return;
+        int len = mCurrentState.getUserText().length();
+        if (mCurrentState.hasAutocompleteText()) {
+            if (selStart > len || selEnd > len) {
+                if (DEBUG) Log.i(TAG, "Autocomplete text is being touched. Make it real.");
+                if (mInputConnection != null) mInputConnection.commitAutocomplete();
+            } else {
+                if (DEBUG) Log.i(TAG, "Touching before the cursor removes autocomplete.");
+                clearAutocompleteText();
+            }
+        }
+        notifyAutocompleteTextStateChanged();
+        updateSelectionForTesting();
+    }
+
+    @Override
+    public void onFocusChanged(boolean focused) {
+        if (DEBUG) Log.i(TAG, "onFocusChanged: " + focused);
+    }
+
+    @Override
+    public void onTextChanged(CharSequence text, int start, int beforeLength, int afterLength) {
+        if (DEBUG) Log.i(TAG, "onTextChanged: " + text);
+        mSpanController.reflectTextUpdateInState(mCurrentState, text);
+        if (mBatchEditNestCount > 0) return; // let endBatchEdit() handles changes from IME.
+        // An external change such as text paste occurred.
+        mLastEditWasTyping = false;
+        clearAutocompleteText();
+    }
+
+    @Override
+    public void onPaste() {
+        if (DEBUG) Log.i(TAG, "onPaste");
+    }
+
+    @Override
+    public String getTextWithAutocomplete() {
+        String retVal = mCurrentState.getText();
+        if (DEBUG) Log.i(TAG, "getTextWithAutocomplete: %s", retVal);
+        return retVal;
+    }
+
+    @Override
+    public String getTextWithoutAutocomplete() {
+        String retVal = mCurrentState.getUserText();
+        if (DEBUG) Log.i(TAG, "getTextWithoutAutocomplete: " + retVal);
+        return retVal;
+    }
+
+    @Override
+    public String getAutocompleteText() {
+        return mCurrentState.getAutocompleteText();
+    }
+
+    @Override
+    public void setIgnoreTextChangeFromAutocomplete(boolean ignore) {
+        if (DEBUG) Log.i(TAG, "setIgnoreText: " + ignore);
+        mIgnoreTextChangeFromAutocomplete = ignore;
+    }
+
+    @Override
+    public void setAutocompleteText(CharSequence userText, CharSequence inlineAutocompleteText) {
+        setAutocompleteTextInternal(userText.toString(), inlineAutocompleteText.toString());
+    }
+
+    private void setAutocompleteTextInternal(String userText, String autocompleteText) {
+        if (DEBUG) Log.i(TAG, "setAutocompleteText: %s[%s]", userText, autocompleteText);
+        mPreviouslySetState.set(userText, autocompleteText, userText.length(), userText.length());
+        // TODO(changwan): avoid any unnecessary removal and addition of autocomplete text when it
+        // is not changed or when it is appended to the existing autocomplete text.
+        if (mInputConnection != null) {
+            mInputConnection.beginBatchEdit();
+            mInputConnection.endBatchEdit();
+        }
+    }
+
+    @Override
+    public boolean shouldAutocomplete() {
+        boolean retVal = mBatchEditNestCount == 0 && mLastEditWasTyping
+                && mCurrentState.isCursorAtEndOfUserText()
+                && isNonCompositionalText(getTextWithoutAutocomplete());
+        if (DEBUG) Log.i(TAG, "shouldAutocomplete: " + retVal);
+        return retVal;
+    }
+
+    @VisibleForTesting
+    public static boolean isNonCompositionalText(String text) {
+        // To start with, we are only activating this for English alphabets, European characters,
+        // numbers and URLs to avoid potential bad interactions with more complex IMEs.
+        // The rationale for including character sets with diacritical marks is that backspacing on
+        // a letter with a diacritical mark most likely deletes the whole character instead of
+        // removing the diacritical mark.
+        // TODO(changwan): also scan for other traditionally non-IME charsets.
+        return NON_COMPOSITIONAL_TEXT_PATTERN.matcher(text).matches();
+    }
+
+    @Override
+    public boolean hasAutocomplete() {
+        boolean retVal = mCurrentState.hasAutocompleteText();
+        if (DEBUG) Log.i(TAG, "hasAutocomplete: " + retVal);
+        return retVal;
+    }
+
+    @Override
+    public InputConnection getInputConnection() {
+        return mInputConnection;
+    }
+
+    private void updateSelectionForTesting() {
+        int selStart = mDelegate.getSelectionStart();
+        int selEnd = mDelegate.getSelectionEnd();
+        if (selStart == mLastUpdateSelStart && selEnd == mLastUpdateSelEnd) return;
+
+        mLastUpdateSelStart = selStart;
+        mLastUpdateSelEnd = selEnd;
+        mDelegate.onUpdateSelectionForTesting(selStart, selEnd);
+    }
+
+    /**
+     * A class to set and remove, or do other operations on Span and SpannableString of autocomplete
+     * text that will be appended to the user text.
+     */
+    private static class SpanController {
+        private final Delegate mDelegate;
+        private BackgroundColorSpan mSpan;
+
+        public SpanController(Delegate delegate) {
+            mDelegate = delegate;
+        }
+
+        public void setSpan(AutocompleteState state) {
+            int sel = state.getSelStart();
+
+            if (mSpan == null) mSpan = new BackgroundColorSpan(mDelegate.getHighlightColor());
+            SpannableString spanString = new SpannableString(state.getAutocompleteText());
+            spanString.setSpan(
+                    mSpan, 0, state.getAutocompleteText().length(), Spanned.SPAN_INTERMEDIATE);
+            Editable editable = mDelegate.getEditableText();
+            editable.append(spanString);
+
+            // Keep the original selection before adding spannable string.
+            Selection.setSelection(editable, sel, sel);
+            if (DEBUG) Log.i(TAG, "setSpan: " + getEditableDebugString(editable));
+        }
+
+        private int getSpanIndex(Editable editable) {
+            if (editable == null || mSpan == null) return -1;
+            return editable.getSpanStart(mSpan); // returns -1 if mSpan is not attached
+        }
+
+        public boolean removeSpan() {
+            Editable editable = mDelegate.getEditableText();
+            int idx = getSpanIndex(editable);
+            if (idx == -1) return false;
+            if (DEBUG) Log.i(TAG, "removeSpan IDX[%d]", idx);
+            editable.removeSpan(mSpan);
+            editable.delete(idx, editable.length());
+            mSpan = null;
+            if (DEBUG) {
+                Log.i(TAG, "removeSpan - after: " + getEditableDebugString(editable));
+            }
+            return true;
+        }
+
+        public void commitSpan() {
+            mDelegate.getEditableText().removeSpan(mSpan);
+        }
+
+        public void reflectTextUpdateInState(AutocompleteState state, CharSequence text) {
+            if (text instanceof Editable) {
+                Editable editable = (Editable) text;
+                int idx = getSpanIndex(editable);
+                if (idx != -1) {
+                    // We do not set autocomplete text here as model should solely control it.
+                    state.setUserText(editable.subSequence(0, idx).toString());
+                    return;
+                }
+            }
+            state.setUserText(text.toString());
+        }
+    }
+
+    private class AutocompleteInputConnection extends InputConnectionWrapper {
+        private final AutocompleteState mPreBatchEditState;
+
+        public AutocompleteInputConnection() {
+            super(null, true);
+            mPreBatchEditState = new AutocompleteState(mCurrentState);
+        }
+
+        private boolean incrementBatchEditCount() {
+            ++mBatchEditNestCount;
+            return super.beginBatchEdit();
+        }
+
+        private boolean decrementBatchEditCount() {
+            --mBatchEditNestCount;
+            boolean retVal = super.endBatchEdit();
+            if (mBatchEditNestCount == 0) updateSelectionForTesting();
+            return retVal;
+        }
+
+        public void commitAutocomplete() {
+            if (DEBUG) Log.i(TAG, "commitAutocomplete");
+            if (!hasAutocomplete()) return;
+            mCurrentState.commitAutocompleteText();
+            // Invalidate mPreviouslySetState.
+            mPreviouslySetState.copyFrom(mCurrentState);
+            mLastEditWasTyping = false;
+            incrementBatchEditCount(); // avoids additional notifyAutocompleteTextStateChanged()
+            mSpanController.commitSpan();
+            decrementBatchEditCount();
+        }
+
+        @Override
+        public boolean beginBatchEdit() {
+            boolean retVal = incrementBatchEditCount();
+            // Note: this should be called after super.beginBatchEdit() to be effective.
+            if (mBatchEditNestCount == 1) {
+                if (DEBUG) Log.i(TAG, "beginBatchEdit");
+                mPreBatchEditState.copyFrom(mCurrentState);
+                mSpanController.removeSpan();
+            }
+            return retVal;
+        }
+
+        private void restoreBackspacedText(String diff) {
+            if (DEBUG) Log.i(TAG, "restoreBackspacedText. diff: " + diff);
+            incrementBatchEditCount(); // avoids additional notifyAutocompleteTextStateChanged()
+            Editable editable = mDelegate.getEditableText();
+            editable.append(diff);
+            decrementBatchEditCount();
+        }
+
+        private boolean setAutocompleteSpan() {
+            assert mBatchEditNestCount == 1;
+            mSpanController.removeSpan();
+            if (DEBUG) {
+                Log.i(TAG, "setAutocompleteSpan. %s->%s", mPreviouslySetState, mCurrentState);
+            }
+            if (!mCurrentState.isCursorAtEndOfUserText()) return false;
+
+            if (mCurrentState.reuseAutocompleteTextIfPrefixExtension(mPreviouslySetState)) {
+                mSpanController.setSpan(mCurrentState);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public boolean endBatchEdit() {
+            if (mBatchEditNestCount > 1) {
+                return decrementBatchEditCount();
+            }
+            if (DEBUG) Log.i(TAG, "endBatchEdit");
+
+            String diff = mCurrentState.getBackwardDeletedTextFrom(mPreBatchEditState);
+            if (diff != null) {
+                // Update selection first such that keyboard app gets what it expects.
+                boolean retVal = decrementBatchEditCount();
+
+                if (mPreBatchEditState.hasAutocompleteText()) {
+                    // Undo delete to retain the last character and only remove autocomplete text.
+                    restoreBackspacedText(diff);
+                }
+                mLastEditWasTyping = false;
+                clearAutocompleteText();
+                return retVal;
+            }
+            if (!setAutocompleteSpan()) {
+                clearAutocompleteText();
+            }
+            boolean retVal = decrementBatchEditCount();
+            // Simply typed some characters or whole text selection has been overridden.
+            if (mCurrentState.isForwardTypedFrom(mPreBatchEditState)
+                    || (mPreBatchEditState.isWholeUserTextSelected()
+                               && mCurrentState.getUserText().length() > 0
+                               && mCurrentState.isCursorAtEndOfUserText())) {
+                mLastEditWasTyping = true;
+            }
+            notifyAutocompleteTextStateChanged();
+            return retVal;
+        }
+
+        @Override
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            if (DEBUG) Log.i(TAG, "commitText: " + text);
+            beginBatchEdit();
+            boolean retVal = super.commitText(text, newCursorPosition);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            if (DEBUG) Log.i(TAG, "setComposingText: " + text);
+            beginBatchEdit();
+            boolean retVal = super.setComposingText(text, newCursorPosition);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean setComposingRegion(int start, int end) {
+            if (DEBUG) Log.i(TAG, "setComposingRegion: [%d,%d]", start, end);
+            beginBatchEdit();
+            boolean retVal = super.setComposingRegion(start, end);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean finishComposingText() {
+            if (DEBUG) Log.i(TAG, "finishComposingText");
+            beginBatchEdit();
+            boolean retVal = super.finishComposingText();
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
+            if (DEBUG) Log.i(TAG, "deleteSurroundingText [%d,%d]", beforeLength, afterLength);
+            beginBatchEdit();
+            boolean retVal = super.deleteSurroundingText(beforeLength, afterLength);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean setSelection(final int start, final int end) {
+            if (DEBUG) Log.i(TAG, "setSelection [%d,%d]", start, end);
+            beginBatchEdit();
+            boolean retVal = super.setSelection(start, end);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean performEditorAction(final int editorAction) {
+            if (DEBUG) Log.i(TAG, "performEditorAction: " + editorAction);
+            beginBatchEdit();
+            commitAutocomplete();
+            boolean retVal = super.performEditorAction(editorAction);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public boolean sendKeyEvent(final KeyEvent event) {
+            if (DEBUG) Log.i(TAG, "sendKeyEvent: " + event.getKeyCode());
+            beginBatchEdit();
+            boolean retVal = super.sendKeyEvent(event);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public ExtractedText getExtractedText(final ExtractedTextRequest request, final int flags) {
+            if (DEBUG) Log.i(TAG, "getExtractedText");
+            beginBatchEdit();
+            ExtractedText retVal = super.getExtractedText(request, flags);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public CharSequence getTextAfterCursor(final int n, final int flags) {
+            if (DEBUG) Log.i(TAG, "getTextAfterCursor");
+            beginBatchEdit();
+            CharSequence retVal = super.getTextAfterCursor(n, flags);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public CharSequence getTextBeforeCursor(final int n, final int flags) {
+            if (DEBUG) Log.i(TAG, "getTextBeforeCursor");
+            beginBatchEdit();
+            CharSequence retVal = super.getTextBeforeCursor(n, flags);
+            endBatchEdit();
+            return retVal;
+        }
+
+        @Override
+        public CharSequence getSelectedText(final int flags) {
+            if (DEBUG) Log.i(TAG, "getSelectedText");
+            beginBatchEdit();
+            CharSequence retVal = super.getSelectedText(flags);
+            endBatchEdit();
+            return retVal;
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index b6d89839..bcdd131e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -511,11 +511,7 @@
         mOmniboxLivenessListener = listener;
     }
 
-    /**
-     * Signal {@link OmniboxLivenessListener} that the omnibox is completely operational now.
-     */
-    @VisibleForTesting
-    public void onOmniboxFullyFunctional() {
+    public void onNativeLibraryReady() {
         if (mOmniboxLivenessListener != null) mOmniboxLivenessListener.onOmniboxFullyFunctional();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
index 70da6ed2..cec5022 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AddressEditor.java
@@ -312,12 +312,13 @@
     }
 
     @Override
-    public void onSubKeysReceived(String[] adminAreas) {
+    public void onSubKeysReceived(String[] adminAreaCodes, String[] adminAreaNames) {
         if (mAdminAreasLoaded) return;
         mAdminAreasLoaded = true;
 
         mAddressFields.put(AddressField.ADMIN_AREA,
-                contains(adminAreas, mProfile.getRegion())
+                (contains(adminAreaCodes, mProfile.getRegion())
+                        || contains(adminAreaNames, mProfile.getRegion()))
                         ? EditorFieldModel.createDropdown()
                         : EditorFieldModel.createTextInput(
                                   EditorFieldModel.INPUT_TYPE_HINT_REGION));
@@ -333,16 +334,16 @@
             // For example, "US" will not add dependent locality to the editor. A "JP" address will
             // start with a person's full name or a with a prefecture name, depending on whether the
             // language code is "ja-Latn" or "ja".
-            addAddressFieldsToEditor(
-                    mRecentlySelectedCountry, Locale.getDefault().getLanguage(), adminAreas);
+            addAddressFieldsToEditor(mRecentlySelectedCountry, Locale.getDefault().getLanguage(),
+                    adminAreaCodes, adminAreaNames);
             // Notify EditorDialog that the fields in the model have changed. EditorDialog should
             // re-read the model and update the UI accordingly.
             mHandler.post(mCountryChangeCallback);
         } else {
             // This should be called when all required fields are put in mAddressField.
             setAddressFieldValuesFromCache();
-            addAddressFieldsToEditor(
-                    mProfile.getCountryCode(), mProfile.getLanguageCode(), adminAreas);
+            addAddressFieldsToEditor(mProfile.getCountryCode(), mProfile.getLanguageCode(),
+                    adminAreaCodes, adminAreaNames);
             mEditorDialog.show(mEditor);
         }
     }
@@ -365,7 +366,7 @@
         // fetch the admin-areas, and show a text-field instead.
         // This is to have the tests independent of the network status.
         if (PersonalDataManager.getInstance().getRequestTimeoutMS() == 0) {
-            onSubKeysReceived(null);
+            onSubKeysReceived(null, null);
             return;
         }
 
@@ -378,8 +379,8 @@
      * Adds fields to the editor model based on the country and language code of
      * the profile that's being edited.
      */
-    private void addAddressFieldsToEditor(
-            String countryCode, String languageCode, String[] adminAreas) {
+    private void addAddressFieldsToEditor(String countryCode, String languageCode,
+            String[] adminAreaCodes, String[] adminAreaNames) {
         mAddressUiComponents =
                 mAutofillProfileBridge.getAddressUiComponents(countryCode, languageCode);
         // In terms of order, country must be the first field.
@@ -395,8 +396,8 @@
                     || component.id == AddressField.DEPENDENT_LOCALITY);
 
             if (component.id == AddressField.ADMIN_AREA && field.isDropdownField()) {
-                field.setDropdownKeyValues(
-                        mAutofillProfileBridge.getAdminAreaDropdownList(adminAreas));
+                field.setDropdownKeyValues(mAutofillProfileBridge.getAdminAreaDropdownList(
+                        adminAreaCodes, adminAreaNames));
             }
 
             // Libaddressinput formats do not always require the full name (RECIPIENT), but
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 658f0e6..e1ab3204 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -1091,7 +1091,8 @@
      * through the form from top to bottom.
      */
     private void updateSectionButtons() {
-        boolean mayEnableButton = true;
+        // Disable edit buttons when the client is checking a selection.
+        boolean mayEnableButton = !mIsClientCheckingSelection;
         for (int i = 0; i < mPaymentContainerLayout.getChildCount(); i++) {
             View child = mPaymentContainerLayout.getChildAt(i);
             if (!(child instanceof PaymentRequestSection)) continue;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
index a5bc8eb5..e4a316e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
@@ -101,12 +101,12 @@
     }
 
     /** @return The list of admin areas sorted by their localized display names. */
-    public static List<DropdownKeyValue> getAdminAreaDropdownList(String[] keys) {
+    public static List<DropdownKeyValue> getAdminAreaDropdownList(
+            String[] adminAreaCodes, String[] adminAreaNames) {
         List<DropdownKeyValue> adminAreas = new ArrayList<>();
 
-        for (int i = 0; i < keys.length; ++i) {
-            // TODO (parastoog): show names, save keys. @crbug.com/691643
-            adminAreas.add(new DropdownKeyValue(keys[i], keys[i]));
+        for (int i = 0; i < adminAreaCodes.length; ++i) {
+            adminAreas.add(new DropdownKeyValue(adminAreaCodes[i], adminAreaNames[i]));
         }
 
         final Collator collator = Collator.getInstance(Locale.getDefault());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
index 514e231..1216b8fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
@@ -24,10 +24,11 @@
      * Launch the data reduction promo, if it needs to be displayed.
      * @return Whether the data reduction promo was displayed.
      */
-    public static boolean launchDataReductionPromo(Activity parentActivity) {
+    public static boolean launchDataReductionPromo(Activity parentActivity, boolean isIncognito) {
         // The promo is displayed if Chrome is launched directly (i.e., not with the intent to
         // navigate to and view a URL on startup), the instance is part of the field trial,
         // and the promo has not been displayed before.
+        if (isIncognito) return false;
         if (!DataReductionPromoUtils.canShowPromos()) return false;
         if (DataReductionPromoUtils.getDisplayedFreOrSecondRunPromo()) return false;
         // Showing the promo dialog in multiwindow mode is broken on Galaxy Note devices:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index cdf82a9218..f7d3275 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -66,14 +66,6 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (shouldDisplayInteractivePasswordEntryEditor()) {
-            mView = inflater.inflate(R.layout.password_entry_editor_interactive, container, false);
-        } else {
-            mView = inflater.inflate(R.layout.password_entry_editor, container, false);
-        }
-        getActivity().setTitle(R.string.password_entry_editor_title);
-        mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService(
-                Context.CLIPBOARD_SERVICE);
         // Extras are set on this intent in class {@link SavePasswordsPreferences}.
         mExtras = getArguments();
         assert mExtras != null;
@@ -81,12 +73,28 @@
         final String name = mExtras.containsKey(SavePasswordsPreferences.PASSWORD_LIST_NAME)
                 ? mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_NAME)
                 : null;
+
+        mException = (name == null);
+        if (shouldDisplayInteractivePasswordEntryEditor()) {
+            if (!mException) {
+                mView = inflater.inflate(
+                        R.layout.password_entry_editor_interactive, container, false);
+            } else {
+                mView = inflater.inflate(R.layout.password_entry_exception, container, false);
+            }
+        } else {
+            mView = inflater.inflate(R.layout.password_entry_editor, container, false);
+        }
+        getActivity().setTitle(R.string.password_entry_editor_title);
+        mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService(
+                Context.CLIPBOARD_SERVICE);
         TextView nameView = (TextView) mView.findViewById(R.id.password_entry_editor_name);
-        if (name != null) {
+        if (!mException) {
             nameView.setText(name);
         } else {
-            nameView.setText(R.string.section_saved_passwords_exceptions);
-            mException = true;
+            if (!shouldDisplayInteractivePasswordEntryEditor()) {
+                nameView.setText(R.string.section_saved_passwords_exceptions);
+            }
         }
         final String url = mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_URL);
         TextView urlView = (TextView) mView.findViewById(R.id.password_entry_editor_url);
@@ -95,9 +103,11 @@
             mKeyguardManager =
                     (KeyguardManager) getActivity().getApplicationContext().getSystemService(
                             Context.KEYGUARD_SERVICE);
-            hidePassword();
-            hookupPasswordButtons();
-            hookupCopyUsernameButton();
+            if (!mException) {
+                hidePassword();
+                hookupPasswordButtons();
+                hookupCopyUsernameButton();
+            }
             hookupCopySiteButton();
         } else {
             hookupCancelDeleteButtons();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index b53bb9f..7f43a36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -80,15 +80,17 @@
         });
 
         UiConfig uiConfig = new UiConfig(mRecyclerView);
+        mRecyclerView.init(uiConfig, mContextMenuManager);
 
         final NewTabPageAdapter adapter = new NewTabPageAdapter(mSuggestionsUiDelegate,
                 /* aboveTheFoldView = */ null, uiConfig, OfflinePageBridge.getForProfile(profile),
                 mContextMenuManager, mTileGroupDelegate);
-        mRecyclerView.init(uiConfig, mContextMenuManager, adapter);
 
         mBottomSheetObserver = new SuggestionsSheetVisibilityChangeObserver(this, activity) {
             @Override
             public void onSheetOpened() {
+                mRecyclerView.setAdapter(adapter);
+
                 mRecyclerView.scrollToPosition(0);
                 adapter.refreshSuggestions();
                 mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened();
@@ -121,6 +123,12 @@
                     SuggestionsMetrics.recordSurfaceFullyVisible();
                 }
             }
+
+            @Override
+            public void onSheetClosed() {
+                super.onSheetClosed();
+                mRecyclerView.setAdapter(null);
+            }
         };
 
         mShadowView = (FadingShadowView) mView.findViewById(R.id.shadow);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
index 3411205..13f6e192 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
@@ -192,11 +192,9 @@
         super.onLayout(changed, l, t, r, b);
     }
 
-    public void init(
-            UiConfig uiConfig, ContextMenuManager contextMenuManager, NewTabPageAdapter adapter) {
+    public void init(UiConfig uiConfig, ContextMenuManager contextMenuManager) {
         mUiConfig = uiConfig;
         mContextMenuManager = contextMenuManager;
-        setAdapter(adapter);
     }
 
     public NewTabPageAdapter getNewTabPageAdapter() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
index 0573d850..3e440d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -231,11 +231,11 @@
             mTab.updateTitle();
             mTab.handleDidFinishNavigation(url, pageTransition);
             mTab.setIsShowingErrorPage(isErrorPage);
-        }
 
-        observers.rewind();
-        while (observers.hasNext()) {
-            observers.next().onUrlUpdated(mTab);
+            observers.rewind();
+            while (observers.hasNext()) {
+                observers.next().onUrlUpdated(mTab);
+            }
         }
 
         FullscreenManager fullscreenManager = mTab.getFullscreenManager();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 54ebfe9..b6fe6ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -159,12 +159,6 @@
     /** Whether the disappearance of the toolbar buttons is currently animating. */
     private boolean mAnimatingToolbarButtonDisappearance;
 
-    /** The current left position of the location bar background. */
-    private int mLocationBarBackgroundLeftPosition;
-
-    /** The current right position of the location bar background. */
-    private int mLocationBarBackgroundRightPosition;
-
     /**
      * Constructs a BottomToolbarPhone object.
      * @param context The Context in which this View object is created.
@@ -356,31 +350,25 @@
     @Override
     protected int getLeftPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
-            mLocationBarBackgroundLeftPosition =
-                    super.getLeftPositionOfLocationBarBackground(visualState);
+            return super.getLeftPositionOfLocationBarBackground(visualState);
         } else {
             int targetPosition = getViewBoundsLeftOfLocationBar(visualState);
             int currentPosition = targetPosition + getLocationBarBackgroundLeftOffset();
-            mLocationBarBackgroundLeftPosition = (int) MathUtils.interpolate(
+            return (int) MathUtils.interpolate(
                     targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
-
-        return mLocationBarBackgroundLeftPosition;
     }
 
     @Override
     protected int getRightPositionOfLocationBarBackground(VisualState visualState) {
         if (!mAnimatingToolbarButtonAppearance && !mAnimatingToolbarButtonDisappearance) {
-            mLocationBarBackgroundRightPosition =
-                    super.getRightPositionOfLocationBarBackground(visualState);
+            return super.getRightPositionOfLocationBarBackground(visualState);
         } else {
             int targetPosition = getViewBoundsRightOfLocationBar(visualState);
             int currentPosition = targetPosition - getLocationBarBackgroundRightOffset();
-            mLocationBarBackgroundRightPosition = (int) MathUtils.interpolate(
+            return (int) MathUtils.interpolate(
                     targetPosition, currentPosition, mToolbarButtonVisibilityPercent);
         }
-
-        return mLocationBarBackgroundRightPosition;
     }
 
     private int getLocationBarBackgroundLeftOffset() {
@@ -733,18 +721,28 @@
 
         float locationBarTranslationX;
         boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mLocationBar);
-
-        if (isLocationBarRtl) {
-            locationBarTranslationX = mLocationBarBackgroundRightPosition
-                    - mUnfocusedLocationBarLayoutWidth - mUnfocusedLocationBarLayoutLeft;
-        } else {
-            locationBarTranslationX =
-                    mUnfocusedLocationBarLayoutLeft + mLocationBarBackgroundLeftPosition;
-        }
-
         FrameLayout.LayoutParams locationBarLayoutParams = getFrameLayoutParams(mLocationBar);
         int currentLeftMargin = locationBarLayoutParams.leftMargin;
-        locationBarTranslationX -= (currentLeftMargin + mToolbarSidePadding);
+        int currentWidth = locationBarLayoutParams.width;
+
+        if (isLocationBarRtl) {
+            // The location bar contents should be aligned with the right side of the toolbar.
+            // If RTL text is displayed in an LTR toolbar, the right position of the location bar
+            // background will change as the location bar background expands/contracts.
+            locationBarTranslationX =
+                    -currentWidth + getRightPositionOfLocationBarBackground(mVisualState);
+
+            if (!mHasVisibleViewPriorToUrlBar) locationBarTranslationX -= mToolbarSidePadding;
+        } else {
+            // The location bar contents should be aligned with the left side of the location bar
+            // background. If LTR text is displayed in an RTL toolbar, the current left position of
+            // the location bar background will change as the location bar background
+            // expands/contracts.
+            locationBarTranslationX = mUnfocusedLocationBarLayoutLeft
+                    + getLeftPositionOfLocationBarBackground(mVisualState) - mToolbarSidePadding;
+        }
+
+        locationBarTranslationX -= currentLeftMargin;
 
         // Get the padding straight from the location bar instead of
         // |mLocationBarBackgroundPadding|, because it might be different in incognito mode.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index f68ad99..160b79c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -188,6 +188,8 @@
     protected boolean mLayoutLocationBarInFocusedMode;
     protected int mUnfocusedLocationBarLayoutWidth;
     protected int mUnfocusedLocationBarLayoutLeft;
+    protected int mUnfocusedLocationBarLayoutRight;
+    protected boolean mHasVisibleViewPriorToUrlBar;
     private boolean mUnfocusedLocationBarUsesTransparentBg;
 
     private int mLocationBarBackgroundAlpha = 255;
@@ -260,7 +262,7 @@
         NEW_TAB_NORMAL
     }
 
-    private VisualState mVisualState = VisualState.NORMAL;
+    protected VisualState mVisualState = VisualState.NORMAL;
     private VisualState mOverlayDrawablesVisualState;
     protected boolean mUseLightToolbarDrawables;
 
@@ -529,12 +531,12 @@
     }
 
     private void updateUnfocusedLocationBarLayoutParams() {
-        boolean hasVisibleViewPriorToUrlBar = false;
+        mHasVisibleViewPriorToUrlBar = false;
         for (int i = 0; i < mLocationBar.getChildCount(); i++) {
             View child = mLocationBar.getChildAt(i);
             if (child == mUrlBar) break;
             if (child.getVisibility() != GONE) {
-                hasVisibleViewPriorToUrlBar = true;
+                mHasVisibleViewPriorToUrlBar = true;
                 break;
             }
         }
@@ -542,7 +544,7 @@
         int leftViewBounds = getViewBoundsLeftOfLocationBar(mVisualState);
         int rightViewBounds = getViewBoundsRightOfLocationBar(mVisualState);
 
-        if (!hasVisibleViewPriorToUrlBar) {
+        if (!mHasVisibleViewPriorToUrlBar) {
             if (ApiCompatibilityUtils.isLayoutRtl(mLocationBar)) {
                 rightViewBounds -= mToolbarSidePadding;
             } else {
@@ -561,6 +563,7 @@
 
         mUnfocusedLocationBarLayoutWidth = rightViewBounds - leftViewBounds;
         mUnfocusedLocationBarLayoutLeft = leftViewBounds;
+        mUnfocusedLocationBarLayoutRight = rightViewBounds;
     }
 
     /**
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6d29d30d..75a05c4 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -716,6 +716,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java",
+  "java/src/org/chromium/chrome/browser/omnibox/AutocompleteState.java",
   "java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelper.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBar.java",
   "java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java",
@@ -726,6 +727,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/OmniboxSuggestion.java",
   "java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java",
   "java/src/org/chromium/chrome/browser/omnibox/OmniboxViewUtil.java",
+  "java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java",
   "java/src/org/chromium/chrome/browser/omnibox/SuggestionAnswer.java",
   "java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBar.java",
@@ -1794,8 +1796,10 @@
   "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java",
   "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java",
+  "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelperUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java",
+  "junit/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeaderTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/geo/VisibleNetworksTrackerTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
index 3ce2934..34e16276 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/ClientManagerTest.java
@@ -18,6 +18,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.MetricsUtils;
@@ -50,6 +51,12 @@
         RequestThrottler.purgeAllEntriesForTesting(context);
         mClientManager = new ClientManager(context);
         RecordHistogram.initialize();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                OriginVerifier.reset();
+            }
+        });
     }
 
     @Test
@@ -162,53 +169,71 @@
     @Test
     @SmallTest
     public void testPostMessageOriginVerification() {
-        Assert.assertTrue(
-                mClientManager.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
+        final ClientManager cm = mClientManager;
+        Assert.assertTrue(cm.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
         // Should always start with no origin.
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // With no prepopulated origins, this verification should fail.
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                // With no prepopulated origins, this verification should fail.
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // If there is a prepopulated origin, we should get a synchronous verification.
-        OriginVerifier.prePopulateVerifiedOriginForTesting(
-                ContextUtils.getApplicationContext().getPackageName(), Uri.parse(URL));
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+                // If there is a prepopulated origin, we should get a synchronous verification.
+                OriginVerifier.addVerifiedOriginForPackage(
+                        ContextUtils.getApplicationContext().getPackageName(), Uri.parse(URL));
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, Uri.parse(URL));
+            }
+        });
+
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return mClientManager.getPostMessageOriginForSessionForTesting(mSession) != null;
+                return cm.getPostMessageOriginForSessionForTesting(mSession) != null;
             }
         });
-        Uri verifiedOrigin = mClientManager.getPostMessageOriginForSessionForTesting(mSession);
-        Assert.assertEquals(IntentHandler.ANDROID_APP_REFERRER_SCHEME, verifiedOrigin.getScheme());
 
-        // initializeWithPostMessageOriginForSession should override without checking origin.
-        mClientManager.initializeWithPostMessageOriginForSession(mSession, null);
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Uri verifiedOrigin = cm.getPostMessageOriginForSessionForTesting(mSession);
+                Assert.assertEquals(
+                        IntentHandler.ANDROID_APP_REFERRER_SCHEME, verifiedOrigin.getScheme());
+
+                // initializeWithPostMessageOriginForSession should override without checking
+                // origin.
+                cm.initializeWithPostMessageOriginForSession(mSession, null);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
+            }
+        });
     }
 
     @Test
     @SmallTest
     public void testPostMessageOriginHttpNotAllowed() {
-        Assert.assertTrue(
-                mClientManager.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
+        final ClientManager cm = mClientManager;
+        Assert.assertTrue(cm.newSession(mSession, mUid, null, new PostMessageHandler(mSession)));
         // Should always start with no origin.
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // With no prepopulated origins, this verification should fail.
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(HTTP_URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Uri uri = Uri.parse(HTTP_URL);
+                // With no prepopulated origins, this verification should fail.
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, uri);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
 
-        // Even if there is a prepopulated origin, non-https origins should get an early return with
-        // false.
-        OriginVerifier.prePopulateVerifiedOriginForTesting(
-                ContextUtils.getApplicationContext().getPackageName(), Uri.parse(HTTP_URL));
-        mClientManager.verifyAndInitializeWithPostMessageOriginForSession(
-                mSession, Uri.parse(HTTP_URL));
-        Assert.assertNull(mClientManager.getPostMessageOriginForSessionForTesting(mSession));
+                // Even if there is a prepopulated origin, non-https origins should get an early
+                // return with false.
+                OriginVerifier.addVerifiedOriginForPackage(
+                        ContextUtils.getApplicationContext().getPackageName(), uri);
+                cm.verifyAndInitializeWithPostMessageOriginForSession(mSession, uri);
+                Assert.assertNull(cm.getPostMessageOriginForSessionForTesting(mSession));
+            }
+        });
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index fb3871b6..40c5ba6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -203,7 +203,8 @@
                 ContextMenuManager contextMenuManager =
                         new ContextMenuManager(mActivityTestRule.getActivity(),
                                 mUiDelegate.getNavigationDelegate(), touchEnabledDelegate);
-                mRecyclerView.init(mUiConfig, contextMenuManager, mAdapter);
+                mRecyclerView.init(mUiConfig, contextMenuManager);
+                mRecyclerView.setAdapter(mAdapter);
 
                 mSuggestion = new SnippetArticleViewHolder(
                         mRecyclerView, contextMenuManager, mUiDelegate, mUiConfig);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 38105ad..0e897e1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -35,8 +35,11 @@
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.ScalableTimeout;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsReceivedListener;
 import org.chromium.chrome.browser.omnibox.LocationBarLayout.OmniboxSuggestionsList;
@@ -70,6 +73,19 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
+@ParameterizedTest.Set(tests = {
+        @ParameterizedTest(parameters = {
+                @Parameter(
+                        tag = CommandLineFlags.Parameter.PARAMETER_TAG)}),
+        @ParameterizedTest(parameters = {
+                @Parameter(
+                        tag = CommandLineFlags.Parameter.PARAMETER_TAG,
+                        arguments = {
+                                @Parameter.Argument(
+                                        name = CommandLineFlags.Parameter.ADD_ARG,
+                                        stringArray = {"enable-features="
+                                                + ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE})
+        })})})
 public class OmniboxTest {
     @Rule
     public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
@@ -541,7 +557,11 @@
         Assert.assertEquals("URL Bar text not autocompleted as expected.", expectedAutocompleteText,
                 urlText.toString());
         Assert.assertEquals(expectedAutocompleteStart, Selection.getSelectionStart(urlText));
-        Assert.assertEquals(expectedAutocompleteEnd, Selection.getSelectionEnd(urlText));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            Assert.assertEquals(expectedAutocompleteEnd, urlText.length());
+        } else {
+            Assert.assertEquals(expectedAutocompleteEnd, Selection.getSelectionEnd(urlText));
+        }
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
index dedb51f..01225c1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -31,8 +31,11 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.base.test.util.parameter.Parameter;
+import org.chromium.base.test.util.parameter.ParameterizedTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -55,6 +58,19 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
+@ParameterizedTest.Set(tests = {
+        @ParameterizedTest(parameters = {
+                @Parameter(
+                        tag = CommandLineFlags.Parameter.PARAMETER_TAG)}),
+        @ParameterizedTest(parameters = {
+                @Parameter(
+                        tag = CommandLineFlags.Parameter.PARAMETER_TAG,
+                        arguments = {
+                                @Parameter.Argument(
+                                        name = CommandLineFlags.Parameter.ADD_ARG,
+                                        stringArray = {"enable-features="
+                                                + ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE})
+        })})})
 public class UrlBarTest {
     // 9000+ chars of goodness
 
@@ -173,6 +189,7 @@
             @Override
             public void run() {
                 urlBar.setText(text);
+                urlBar.setSelection(text.length());
             }
         });
 
@@ -231,7 +248,7 @@
         setAutocomplete(urlBar, "test", "ing is fun");
         setTextAndVerifyNoAutocomplete(urlBar, "new string");
 
-        // Replace part of the non-autocomplete text and see that the autocomplete is cleared.
+        // Replace part of the non-autocomplete text
         setTextAndVerifyNoAutocomplete(urlBar, "test");
         setAutocomplete(urlBar, "test", "ing is fun");
         AutocompleteState state = getAutocompleteState(urlBar, new Runnable() {
@@ -241,10 +258,18 @@
             }
         });
         Assert.assertFalse(state.hasAutocomplete);
-        Assert.assertEquals("tasting is fun", state.textWithoutAutocomplete);
-        Assert.assertEquals("tasting is fun", state.textWithAutocomplete);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: new model clears autocomplete text when non-IME change has been made.
+            // The autocomplete gets removed.
+            Assert.assertEquals("tast", state.textWithoutAutocomplete);
+            Assert.assertEquals("tast", state.textWithAutocomplete);
+        } else {
+            // The autocomplete gets committed.
+            Assert.assertEquals("tasting is fun", state.textWithoutAutocomplete);
+            Assert.assertEquals("tasting is fun", state.textWithAutocomplete);
+        }
 
-        // Replace part of the autocomplete text and see that the autocomplete is cleared.
+        // Replace part of the autocomplete text.
         setTextAndVerifyNoAutocomplete(urlBar, "test");
         setAutocomplete(urlBar, "test", "ing is fun");
         state = getAutocompleteState(urlBar, new Runnable() {
@@ -254,8 +279,16 @@
             }
         });
         Assert.assertFalse(state.hasAutocomplete);
-        Assert.assertEquals("testing no fun", state.textWithoutAutocomplete);
-        Assert.assertEquals("testing no fun", state.textWithAutocomplete);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: new model clears autocomplete text when non-IME change has been made.
+            // The autocomplete gets removed.
+            Assert.assertEquals("test", state.textWithoutAutocomplete);
+            Assert.assertEquals("test", state.textWithAutocomplete);
+        } else {
+            // The autocomplete gets committed.
+            Assert.assertEquals("testing no fun", state.textWithoutAutocomplete);
+            Assert.assertEquals("testing no fun", state.textWithAutocomplete);
+        }
     }
 
     private void verifySelectionState(
@@ -316,8 +349,11 @@
         // Verify that setting a selection range before the autocomplete clears it.
         verifySelectionState("test", "ing is fun", 0, 4, false, "test", "test", true, "test");
 
-        // Verify that setting a selection at the start of the autocomplete clears it.
-        verifySelectionState("test", "ing is fun", 4, 4, false, "test", "test", true, "test");
+        // Note: with new model touching the beginning of the autocomplete text is a no-op.
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Verify that setting a selection at the start of the autocomplete clears it.
+            verifySelectionState("test", "ing is fun", 4, 4, false, "test", "test", true, "test");
+        }
 
         // Verify that setting a selection range that covers a portion of the non-autocomplete
         // and autocomplete text does not delete the autocomplete text.
@@ -329,11 +365,18 @@
         verifySelectionState("test", "ing is fun", 0, 14,
                 false, "testing is fun", "testing is fun", true, "testing is fun");
 
-        // Verify that setting a selection at the end of the text does not delete the autocomplete
-        // text.
-        verifySelectionState("test", "ing is fun", 14, 14,
-                false, "testing is fun", "testing is fun", false, "testing is fun");
-
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: with new model touching the beginning of the autocomplete text is a no-op.
+            // Verify that setting a selection at the end of the text does not delete the
+            // autocomplete text.
+            verifySelectionState("test", "ing is fun", 14, 14, false, "testing is fun",
+                    "testing is fun", true, "testing is fun");
+        } else {
+            // Verify that setting a selection at the end of the text does not delete the
+            // autocomplete text.
+            verifySelectionState("test", "ing is fun", 14, 14, false, "testing is fun",
+                    "testing is fun", false, "testing is fun");
+        }
         // Verify that setting a selection in the middle of the autocomplete text does not delete
         // the autocomplete text.
         verifySelectionState("test", "ing is fun", 9, 9,
@@ -344,16 +387,27 @@
         verifySelectionState("test", "ing is fun", 8, 11,
                 false, "testing is fun", "testing is fun", true, "testing is fun");
 
-        // Verify that setting the same selection does not clear the autocomplete text.
-        // As we do not expect the suggestions to be refreshed, we test this slightly differently
-        // than the other cases.
+        // Select autocomplete text. As we do not expect the suggestions to be refreshed, we test
+        // this slightly differently than the other cases.
         stubLocationBarAutocomplete();
         setTextAndVerifyNoAutocomplete(urlBar, "test");
         setAutocomplete(urlBar, "test", "ing is fun");
         AutocompleteState state = setSelection(urlBar, 4, 14);
-        Assert.assertEquals("Has autocomplete", true, state.hasAutocomplete);
-        Assert.assertEquals("Text w/o Autocomplete", "test", state.textWithoutAutocomplete);
-        Assert.assertEquals("Text w/ Autocomplete", "testing is fun", state.textWithAutocomplete);
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: with new model selecting the autocomplete text will commit autocomplete.
+            Assert.assertEquals("Has autocomplete", false, state.hasAutocomplete);
+            Assert.assertEquals(
+                    "Text w/o Autocomplete", "testing is fun", state.textWithoutAutocomplete);
+            Assert.assertEquals(
+                    "Text w/ Autocomplete", "testing is fun", state.textWithAutocomplete);
+        } else {
+            // Verify that setting the same selection does not clear the autocomplete text.
+            Assert.assertEquals("Has autocomplete", true, state.hasAutocomplete);
+            Assert.assertEquals("Text w/o Autocomplete", "test", state.textWithoutAutocomplete);
+            Assert.assertEquals(
+                    "Text w/ Autocomplete", "testing is fun", state.textWithAutocomplete);
+        }
     }
 
     /**
@@ -396,10 +450,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                urlBar.getInputConnection().beginBatchEdit();
-                urlBar.setText(textToBeEntered);
-                urlBar.setSelection(textToBeEntered.length());
-                urlBar.getInputConnection().endBatchEdit();
+                urlBar.getInputConnection().commitText(textToBeEntered, 1);
             }
         });
         autocompleteHelper.waitForCallback(0);
@@ -469,6 +520,11 @@
         mActivityTestRule.startMainActivityOnBlankPage();
         stubLocationBarAutocomplete();
         final UrlBar urlBar = getUrlBar();
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: with the new model, we remove autocomplete text at the beginning of a batch
+            // edit and add it at the end of a batch edit.
+            return;
+        }
         toggleFocusAndIgnoreImeOperations(urlBar, true);
 
         setTextAndVerifyNoAutocomplete(urlBar, "test");
@@ -491,7 +547,6 @@
                 urlBar.getInputConnection().endBatchEdit();
             }
         });
-
         // Ensure that after batch mode has ended that the autocomplete is cleared due to the
         // invalid selection range.
         state = getAutocompleteState(urlBar, null);
@@ -564,16 +619,14 @@
         OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, true);
 
         // Valid case (cursor at the end of text, single character, matches previous autocomplete).
+        setTextAndVerifyNoAutocomplete(urlBar, "g");
         setAutocomplete(urlBar, "g", "oogle.com");
         AutocompleteState state = getAutocompleteState(urlBar, new Runnable() {
             @Override
             // TODO(crbug.com/635567): Fix this properly.
             @SuppressLint("SetTextI18n")
             public void run() {
-                urlBar.getInputConnection().beginBatchEdit();
-                urlBar.setText("go");
-                urlBar.setSelection(2);
-                urlBar.getInputConnection().endBatchEdit();
+                urlBar.getInputConnection().commitText("o", 1);
             }
         });
         Assert.assertTrue(state.hasAutocomplete);
@@ -581,6 +634,7 @@
         Assert.assertEquals("go", state.textWithoutAutocomplete);
 
         // Invalid case (cursor not at the end of the text)
+        setTextAndVerifyNoAutocomplete(urlBar, "g");
         setAutocomplete(urlBar, "g", "oogle.com");
         state = getAutocompleteState(urlBar, new Runnable() {
             @Override
@@ -588,42 +642,44 @@
             @SuppressLint("SetTextI18n")
             public void run() {
                 urlBar.getInputConnection().beginBatchEdit();
-                urlBar.setText("go");
-                urlBar.setSelection(0);
+                urlBar.getInputConnection().commitText("o", 1);
+                urlBar.getInputConnection().setSelection(0, 0);
                 urlBar.getInputConnection().endBatchEdit();
             }
         });
         Assert.assertFalse(state.hasAutocomplete);
 
         // Invalid case (next character did not match previous autocomplete)
+        setTextAndVerifyNoAutocomplete(urlBar, "g");
         setAutocomplete(urlBar, "g", "oogle.com");
         state = getAutocompleteState(urlBar, new Runnable() {
             @Override
             // TODO(crbug.com/635567): Fix this properly.
             @SuppressLint("SetTextI18n")
             public void run() {
-                urlBar.getInputConnection().beginBatchEdit();
-                urlBar.setText("ga");
-                urlBar.setSelection(2);
-                urlBar.getInputConnection().endBatchEdit();
+                urlBar.getInputConnection().commitText("a", 1);
             }
         });
         Assert.assertFalse(state.hasAutocomplete);
 
-        // Invalid case (multiple characters entered instead of 1)
+        // Multiple characters entered instead of 1.
+        setTextAndVerifyNoAutocomplete(urlBar, "g");
         setAutocomplete(urlBar, "g", "oogle.com");
         state = getAutocompleteState(urlBar, new Runnable() {
             @Override
             // TODO(crbug.com/635567): Fix this properly.
             @SuppressLint("SetTextI18n")
             public void run() {
-                urlBar.getInputConnection().beginBatchEdit();
-                urlBar.setText("googl");
-                urlBar.setSelection(5);
-                urlBar.getInputConnection().endBatchEdit();
+                urlBar.getInputConnection().commitText("oogl", 1);
             }
         });
-        Assert.assertFalse(state.hasAutocomplete);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: new model allows multiple characters because usually keyboard app's UI and
+            // InputConnection threads are separated and user may type fast enough.
+            Assert.assertTrue(state.hasAutocomplete);
+        } else {
+            Assert.assertFalse(state.hasAutocomplete);
+        }
     }
 
     @Test
@@ -737,12 +793,22 @@
                 urlBar.getInputConnection().setComposingText("f", 1);
             }
         });
-        Assert.assertFalse(state.hasAutocomplete);
 
         Editable urlText = getUrlBarText(urlBar);
-        Assert.assertEquals("chrome://f", urlText.toString());
-        Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 9);
-        Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 10);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: the new model hides autocomplete text from IME.
+            // setComposingRegion fails because autocomplete is hidden from IME. In reality, IME
+            // shouldn't do this.
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://ff", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 10);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 11);
+        } else {
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://f", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 9);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 10);
+        }
 
         // Test with > 1 characters in composition.
 
@@ -756,12 +822,22 @@
                 urlBar.getInputConnection().setComposingText("fl", 1);
             }
         });
-        Assert.assertFalse(state.hasAutocomplete);
-
         urlText = getUrlBarText(urlBar);
-        Assert.assertEquals("chrome://fl", urlText.toString());
-        Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 9);
-        Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 11);
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: the new model hides autocomplete text from IME.
+            // setComposingRegion fails because autocomplete is hidden from IME. In reality, IME
+            // shouldn't do this.
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://flfl", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 11);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 13);
+        } else {
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://fl", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 9);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 11);
+        }
 
         // Test with non-matching composition.  Should just append to the URL text.
 
@@ -794,12 +870,21 @@
                 urlBar.getInputConnection().setComposingText("chrome://f", 1);
             }
         });
-        Assert.assertFalse(state.hasAutocomplete);
-
         urlText = getUrlBarText(urlBar);
-        Assert.assertEquals("chrome://f", urlText.toString());
-        Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 0);
-        Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 10);
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE)) {
+            // Note: the new model hides autocomplete text from IME.
+            // setComposingRegion fails because autocomplete is hidden from IME. In reality, IME
+            // shouldn't do this.
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://fchrome://f", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 10);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 20);
+        } else {
+            Assert.assertFalse(state.hasAutocomplete);
+            Assert.assertEquals("chrome://f", urlText.toString());
+            Assert.assertEquals(BaseInputConnection.getComposingSpanStart(urlText), 0);
+            Assert.assertEquals(BaseInputConnection.getComposingSpanEnd(urlText), 10);
+        }
 
         // Test with composition text longer than the URL text.  Shouldn't crash and should
         // just append text.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
index 109ae734..12474f38 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java
@@ -4,6 +4,7 @@
 package org.chromium.chrome.browser.omnibox;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.inOrder;
@@ -12,11 +13,11 @@
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
@@ -26,45 +27,60 @@
 import org.robolectric.shadows.ShadowLog;
 
 import org.chromium.base.Log;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
 /**
  * A robolectric test for {@link AutocompleteEditText} class.
+ * TODO(changwan): switch to ParameterizedRobolectricTest once crbug.com/733324 is fixed.
  */
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 public class AutocompleteEditTextTest {
-    private static final String TAG = "cr_AutocompleteEdit";
+    private static final String TAG = "cr_AutocompleteTest";
+
     private static final boolean DEBUG = false;
 
+    @Rule
+    public Features.Processor mProcessor = new Features.Processor();
+
     private InOrder mInOrder;
     private AutocompleteEditText mAutocomplete;
     private Context mContext;
     private InputConnection mInputConnection;
-    private BaseInputConnection mDummyTargetInputConnection;
-    private AutocompleteEmbedder mEmbedder;
+    private Verifier mVerifier;
 
-    // This is needed to limit the target of inOrder#verify.
-    private static class AutocompleteEmbedder {
+    // Limits the target of InOrder#verify.
+    private static class Verifier {
         public void onAutocompleteTextStateChanged(boolean updateDisplay) {
-            if (DEBUG) Log.i(TAG, "onAutocompleteTextStateChanged");
+            if (DEBUG) Log.i(TAG, "onAutocompleteTextStateChanged: " + updateDisplay);
+        }
+
+        public void onUpdateSelection(int selStart, int selEnd) {
+            if (DEBUG) Log.i(TAG, "onUpdateSelection: [%d,%d]", selStart, selEnd);
         }
     }
 
-    private static class TestAutocompleteEditText extends AutocompleteEditText {
-        private AutocompleteEmbedder mEmbedder;
-
-        public TestAutocompleteEditText(
-                AutocompleteEmbedder embedder, Context context, AttributeSet attrs) {
+    private class TestAutocompleteEditText extends AutocompleteEditText {
+        public TestAutocompleteEditText(Context context, AttributeSet attrs) {
             super(context, attrs);
-            mEmbedder = embedder;
+            if (DEBUG) Log.i(TAG, "TestAutocompleteEditText constructor");
         }
 
         @Override
         public void onAutocompleteTextStateChanged(boolean updateDisplay) {
-            // This function is called in super(), so mEmbedder may be null.
-            if (mEmbedder != null) {
-                mEmbedder.onAutocompleteTextStateChanged(updateDisplay);
+            // This function is called in super(), so mVerifier may be null.
+            if (mVerifier != null) {
+                mVerifier.onAutocompleteTextStateChanged(updateDisplay);
+            }
+        }
+
+        @Override
+        public void onUpdateSelectionForTesting(int selStart, int selEnd) {
+            // This function is called in super(), so mVerifier may be null.
+            if (mVerifier != null) {
+                mVerifier.onUpdateSelection(selStart, selEnd);
             }
         }
 
@@ -74,24 +90,31 @@
         }
     }
 
+    public AutocompleteEditTextTest() {
+        if (DEBUG) ShadowLog.stream = System.out;
+    }
+
+    private boolean isUsingSpannableModel() {
+        return ChromeFeatureList.isEnabled(ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE);
+    }
+
     @Before
-    public void setUp() throws Exception {
-        ShadowLog.stream = System.out;
+    public void setUp() {
         if (DEBUG) Log.i(TAG, "setUp started.");
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        mEmbedder = spy(new AutocompleteEmbedder());
-        mAutocomplete = new TestAutocompleteEditText(mEmbedder, mContext, null);
+        mVerifier = spy(new Verifier());
+        mAutocomplete = new TestAutocompleteEditText(mContext, null);
         assertNotNull(mAutocomplete);
-        // Note: this cannot catch the first {@link
-        // AutocompleteEditText#onAutocompleteTextStateChanged(boolean)}, which is caused
-        // by View constructor's call to setText().
-        mInOrder = inOrder(mEmbedder);
+        mInOrder = inOrder(mVerifier);
         assertTrue(mAutocomplete.requestFocus());
         assertNotNull(mAutocomplete.onCreateInputConnection(new EditorInfo()));
         mInputConnection = mAutocomplete.getInputConnection();
         assertNotNull(mInputConnection);
         mInOrder.verifyNoMoreInteractions();
+        // Feeder should call this at the beginning.
+        mAutocomplete.setIgnoreTextChangesForAutocomplete(false);
+
         if (DEBUG) Log.i(TAG, "setUp finished.");
     }
 
@@ -103,27 +126,376 @@
     }
 
     @Test
-    public void testAppend_CommitText() {
-        // Feeder should call this at the beginning.
-        mAutocomplete.setIgnoreTextChangesForAutocomplete(false);
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testAppend_CommitTextWithSpannableModel() {
+        internalTestAppend_CommitText();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testAppend_CommitTextWithoutSpannableModel() {
+        internalTestAppend_CommitText();
+    }
+
+    private void internalTestAppend_CommitText() {
         // User types "h".
         assertTrue(mInputConnection.commitText("h", 1));
-        mInOrder.verify(mEmbedder).onAutocompleteTextStateChanged(true);
-        // User types "hello".
-        assertTrue(mInputConnection.commitText("ello", 1));
-        mInOrder.verify(mEmbedder).onAutocompleteTextStateChanged(true);
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(1, 1);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(1, 1);
+        }
         mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+
+        // The controller kicks in.
+        mAutocomplete.setAutocompleteText("h", "ello world");
+        // The non-spannable model changes selection in two steps.
+        if (!isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(11, 11);
+            mInOrder.verify(mVerifier).onUpdateSelection(1, 11);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+
+        // User types "he".
+        assertTrue(mInputConnection.commitText("e", 1));
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(2, 2);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onUpdateSelection(2, 11);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        // The controller kicks in.
+        mAutocomplete.setAutocompleteText("he", "llo world");
+        mInOrder.verifyNoMoreInteractions();
+        assertTexts("he", "llo world");
+        assertTrue(mAutocomplete.shouldAutocomplete());
+
+        // User types "hello".
+        assertTrue(mInputConnection.commitText("llo", 1));
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
         // The controller kicks in.
         mAutocomplete.setAutocompleteText("hello", " world");
+        if (!isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(11, 11);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 11);
+        }
+        mInOrder.verifyNoMoreInteractions();
         assertTexts("hello", " world");
+        assertTrue(mAutocomplete.shouldAutocomplete());
+
+        // User types a space.
         assertTrue(mInputConnection.beginBatchEdit());
         assertTrue(mInputConnection.commitText(" ", 1));
-        assertTexts("hello ", "world");
+        assertFalse(mAutocomplete.shouldAutocomplete());
+
         mInOrder.verifyNoMoreInteractions();
         assertTrue(mInputConnection.endBatchEdit());
-        mInOrder.verify(mEmbedder).onAutocompleteTextStateChanged(true);
+
+        // Autocomplete text gets redrawn.
+        assertTexts("hello ", "world");
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(6, 6);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(6, 11);
+        }
+
         mAutocomplete.setAutocompleteText("hello ", "world");
         assertTexts("hello ", "world");
         mInOrder.verifyNoMoreInteractions();
     }
-}
\ No newline at end of file
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testAppend_SetComposingTextWithSpannableModel() {
+        internalTestAppend_SetComposingText();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testAppend_SetComposingTextWithoutSpannableModel() {
+        internalTestAppend_SetComposingText();
+    }
+
+    private void internalTestAppend_SetComposingText() {
+        // User types "h".
+        assertTrue(mInputConnection.setComposingText("h", 1));
+
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(1, 1);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(1, 1);
+        }
+        mInOrder.verifyNoMoreInteractions();
+
+        // The old model does not allow autocompletion here.
+        assertEquals(isUsingSpannableModel(), mAutocomplete.shouldAutocomplete());
+        if (isUsingSpannableModel()) {
+            // The controller kicks in.
+            mAutocomplete.setAutocompleteText("h", "ello world");
+            assertTexts("h", "ello world");
+        } else {
+            assertTexts("h", "");
+        }
+        mInOrder.verifyNoMoreInteractions();
+
+        // User types "hello".
+        assertTrue(mInputConnection.setComposingText("hello", 1));
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        if (isUsingSpannableModel()) {
+            assertTexts("hello", " world");
+        } else {
+            // The old model does not work with composition.
+            assertTexts("hello", "");
+        }
+
+        // The old model does not allow autocompletion here.
+        assertEquals(isUsingSpannableModel(), mAutocomplete.shouldAutocomplete());
+        if (isUsingSpannableModel()) {
+            // The controller kicks in.
+            mAutocomplete.setAutocompleteText("hello", " world");
+            assertTexts("hello", " world");
+        } else {
+            assertTexts("hello", "");
+        }
+        mInOrder.verifyNoMoreInteractions();
+
+        // User types a space.
+        assertTrue(mInputConnection.beginBatchEdit());
+        assertTrue(mInputConnection.finishComposingText());
+        assertTrue(mInputConnection.commitText(" ", 1));
+
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mInputConnection.endBatchEdit());
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(6, 6);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(6, 6);
+        }
+        mInOrder.verifyNoMoreInteractions();
+
+        if (isUsingSpannableModel()) {
+            // Autocomplete text has been drawn at endBatchEdit().
+            assertTexts("hello ", "world");
+        } else {
+            assertTexts("hello ", "");
+        }
+
+        // The old model can also autocomplete now.
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        mAutocomplete.setAutocompleteText("hello ", "world");
+        assertTexts("hello ", "world");
+        if (!isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(6, 11);
+        }
+        mInOrder.verifyNoMoreInteractions();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testDelete_SetComposingTextWithSpannableModel() {
+        // User types "hello".
+        assertTrue(mInputConnection.setComposingText("hello", 1));
+
+        mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        // The controller kicks in.
+        mAutocomplete.setAutocompleteText("hello", " world");
+        assertTexts("hello", " world");
+        mInOrder.verifyNoMoreInteractions();
+
+        // User deletes 'o'.
+        assertTrue(mInputConnection.setComposingText("hell", 1));
+        mInOrder.verify(mVerifier).onUpdateSelection(4, 4);
+        // We restore 'o', and clears autocomplete text instead.
+        mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        mInOrder.verifyNoMoreInteractions();
+        assertFalse(mAutocomplete.shouldAutocomplete());
+        assertTexts("hello", "");
+
+        // Keyboard app checks the current state.
+        assertEquals("hello", mInputConnection.getTextBeforeCursor(10, 0));
+        mInOrder.verifyNoMoreInteractions();
+        assertFalse(mAutocomplete.shouldAutocomplete());
+        assertTexts("hello", "");
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testSelect_SelectAutocompleteWithSpannableModel() {
+        internalTestSelect_SelectAutocomplete();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testSelect_SelectAutocompleteWithoutSpannableModel() {
+        internalTestSelect_SelectAutocomplete();
+    }
+
+    private void internalTestSelect_SelectAutocomplete() {
+        // User types "hello".
+        assertTrue(mInputConnection.commitText("hello", 1));
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        // The controller kicks in.
+        mAutocomplete.setAutocompleteText("hello", " world");
+        assertTexts("hello", " world");
+        if (!isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(11, 11);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 11);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        // User touches autocomplete text.
+        mAutocomplete.setSelection(7);
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(7, 7);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+            mInOrder.verify(mVerifier).onUpdateSelection(7, 7);
+        }
+        assertFalse(mAutocomplete.shouldAutocomplete());
+        assertTexts("hello world", "");
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testSelect_SelectUserTextWithSpannableModel() {
+        internalTestSelect_SelectUserText();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testSelect_SelectUserTextWithoutSpannableModel() {
+        internalTestSelect_SelectUserText();
+    }
+
+    private void internalTestSelect_SelectUserText() {
+        // User types "hello".
+        assertTrue(mInputConnection.commitText("hello", 1));
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(true);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 5);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        assertTrue(mAutocomplete.shouldAutocomplete());
+        // The controller kicks in.
+        mAutocomplete.setAutocompleteText("hello", " world");
+        assertTexts("hello", " world");
+        if (!isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(11, 11);
+            mInOrder.verify(mVerifier).onUpdateSelection(5, 11);
+        }
+        mInOrder.verifyNoMoreInteractions();
+        // User touches the user text.
+        mAutocomplete.setSelection(3);
+        if (isUsingSpannableModel()) {
+            mInOrder.verify(mVerifier).onUpdateSelection(3, 3);
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+        } else {
+            mInOrder.verify(mVerifier).onAutocompleteTextStateChanged(false);
+            mInOrder.verify(mVerifier).onUpdateSelection(3, 3);
+        }
+        assertFalse(mAutocomplete.shouldAutocomplete());
+        // Autocomplete text is removed.
+        assertTexts("hello", "");
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testAppend_AfterSelectAllWithSpannableModel() {
+        internalTestAppend_AfterSelectAll();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testAppend_AfterSelectAllWithoutSpannableModel() {
+        internalTestAppend_AfterSelectAll();
+    }
+
+    private void internalTestAppend_AfterSelectAll() {
+        final String url = "https://www.google.com/";
+        mAutocomplete.setText(url);
+        mAutocomplete.setSelection(0, url.length());
+        // User types "h" - note that this is also starting character of the URL. The selection gets
+        // replaced by what user types.
+        assertTrue(mInputConnection.commitText("h", 1));
+        // We want to allow inline autocomplete when the user overrides an existing URL.
+        assertTrue(mAutocomplete.shouldAutocomplete());
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = true))
+    public void testIgnoreAndGetWithSpannableModel() {
+        internalTestIgnoreAndGet();
+    }
+
+    @Test
+    @Features(@Features.Register(
+            value = ChromeFeatureList.SPANNABLE_INLINE_AUTOCOMPLETE, enabled = false))
+    public void testIgnoreAndGetWithoutSpannableModel() {
+        internalTestIgnoreAndGet();
+    }
+
+    private void internalTestIgnoreAndGet() {
+        final String url = "https://www.google.com/";
+        mAutocomplete.setIgnoreTextChangesForAutocomplete(true);
+        mAutocomplete.setText(url);
+        mAutocomplete.setIgnoreTextChangesForAutocomplete(false);
+        mInputConnection.getTextBeforeCursor(1, 1);
+        mInOrder.verifyNoMoreInteractions();
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java
new file mode 100644
index 0000000..5a0bfa0
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/AutocompleteStateUnitTest.java
@@ -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.
+package org.chromium.chrome.browser.omnibox;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Unit tests for {@link AutocompleteState}.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class AutocompleteStateUnitTest {
+    @Test
+    public void testIsProperSubstring() {
+        assertTrue(AutocompleteState.isPrefix("ab", "abc"));
+
+        assertFalse(AutocompleteState.isPrefix("ab", "ab"));
+        assertFalse(AutocompleteState.isPrefix("abc", "ab"));
+    }
+
+    @Test
+    public void testIsForwardTyped() {
+        assertTrue(new AutocompleteState("abc", "de", 3, 3)
+                           .isForwardTypedFrom(new AutocompleteState("ab", "c", 2, 2)));
+        assertTrue(new AutocompleteState("abcd", "e", 4, 4)
+                           .isForwardTypedFrom(new AutocompleteState("ab", "c", 2, 2)));
+
+        assertFalse(new AutocompleteState("abc", "de", 3, 3)
+                            .isForwardTypedFrom(new AutocompleteState("abc", "", 3, 3)));
+        assertFalse(new AutocompleteState("abc", "de", 3, 3)
+                            .isForwardTypedFrom(new AutocompleteState("abcd", "e", 4, 4)));
+    }
+
+    @Test
+    public void testGetBackwardDeletedTextFrom() {
+        assertEquals("c",
+                new AutocompleteState("ab", "", 2, 2)
+                        .getBackwardDeletedTextFrom(new AutocompleteState("abc", "d", 3, 3)));
+        // A string is not seen as backward deleted from itself.
+        assertEquals(null,
+                new AutocompleteState("ab", "", 2, 2)
+                        .getBackwardDeletedTextFrom(new AutocompleteState("ab", "d", 2, 2)));
+        // Reversed.
+        assertEquals(null,
+                new AutocompleteState("abc", "", 3, 3)
+                        .getBackwardDeletedTextFrom(new AutocompleteState("ab", "d", 2, 2)));
+        // Selection not valid.
+        assertNull(new AutocompleteState("ab", "", 2, 2)
+                           .getBackwardDeletedTextFrom(new AutocompleteState("abc", "d", 2, 3)));
+        assertNull(new AutocompleteState("ab", "", 2, 3)
+                           .getBackwardDeletedTextFrom(new AutocompleteState("abc", "d", 2, 2)));
+    }
+
+    private void verifyReuseAutocompleteText(AutocompleteState s1, AutocompleteState s2,
+            boolean expectedRetVal, String expectedAutocompleteText) {
+        assertEquals(expectedRetVal, s2.reuseAutocompleteTextIfPrefixExtension(s1));
+        assertEquals(expectedAutocompleteText, s2.getAutocompleteText());
+    }
+
+    @Test
+    public void testReuseAutocompleteText() {
+        verifyReuseAutocompleteText(new AutocompleteState("ab", "cd", 2, 2),
+                new AutocompleteState("abc", "", 3, 3), true, "d");
+        verifyReuseAutocompleteText(new AutocompleteState("ab", "dc", 2, 2),
+                new AutocompleteState("ab", "", 2, 2), true, "dc");
+
+        // The new state cannot reuse autocomplete text.
+        verifyReuseAutocompleteText(new AutocompleteState("ab", "dc", 2, 2),
+                new AutocompleteState("abc", "a", 3, 3), false, "a");
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java
new file mode 100644
index 0000000..3fc68dc
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java
@@ -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.
+package org.chromium.chrome.browser.omnibox;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Unit tests for {@link SpannableAutocompleteEditTextModel}.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class SpannableAutocompleteEditTextModelUnitTest {
+    @Test
+    public void testNonCompositionalText() {
+        assertTrue(SpannableAutocompleteEditTextModel.isNonCompositionalText("http://123.com"));
+        assertTrue(SpannableAutocompleteEditTextModel.isNonCompositionalText("goo"));
+        assertFalse(SpannableAutocompleteEditTextModel.isNonCompositionalText("네이버"));
+        assertFalse(SpannableAutocompleteEditTextModel.isNonCompositionalText("네"));
+        assertFalse(SpannableAutocompleteEditTextModel.isNonCompositionalText("123네이버"));
+    }
+}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 45483c7b..712beec2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -192,6 +192,11 @@
         <part file="settings_strings.grdp" />
       </if>
 
+      <!-- MD Extensions specific strings -->
+      <if expr="enable_extensions">
+        <part file="md_extensions_strings.grdp" />
+      </if>
+
       <!-- TODO add all of your "string table" messages here.  Remember to
       change nontranslateable parts of the messages into placeholders (using the
       <ph> element).  You can also use the 'grit add' tool to help you identify
@@ -4224,156 +4229,6 @@
         <message name="IDS_EXTENSIONS_LOG_LEVEL_ERROR" desc="Alt-text indicating a high severity level for the error icon in the chrome://extensions page.">
           Error
         </message>
-        <message name="IDS_MD_EXTENSIONS_DEVELOPER_MODE" desc="The text displayed next to the checkbox to toggle developer mode in the extensions page.">
-          Developer mode
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ERROR_PAGE_HEADING" desc="The heading of the page displaying an extension's errors.">
-          Errors
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_ERRORS" desc="The label of the button to bring the user to the page showing an extension's errors.">
-          Errors
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_ID" desc="The text for the label next to the extension id.">
-          &lt;span&gt;ID:&lt;/span&gt;<ph name="EXTENSION_ID">$1<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_INSPECT_VIEWS" desc="The text next to any inspectable views for an extension.">
-          Inspect views:
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_INSPECT_VIEWS_EXTRA" desc="The text to indicate there are additional inspectable views that aren't listed.">
-          <ph name="NUMBER_OF_VIEWS">$1<ex>2</ex></ph> more...
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_ALLOW_INCOGNITO" desc="The text next to the checkbox to enable an extension in incognito mode.">
-          Allow in incognito
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_DEPENDENCIES" desc="The label above a list of any extensions that depend on this extension.">
-          The following extensions depend on this extension:
-        </message>
-        <message name="IDS_MD_EXTENSIONS_DEPENDENT_ENTRY" desc="An item in the list of extensions that depend on this extension. 'NAME_PH' is the name of the extension that depends on this extension, and 'ID_PH' is the id of the extension that depends on this extension">
-          <ph name="NAME_PH">$1<ex>AdBlock</ex></ph> (ID: <ph name="ID_PH">$2<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>)
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_DESCRIPTION" desc="The label above the description for a given item.">
-          Description
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_DETAILS" desc="The text on the button to show more details for a given extension.">
-          Details
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_ID_HEADING" desc="The heading above the ID of the extension.">
-          ID
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_OFF" desc="The label to indicate that a specific extension is not currently enabled.">
-          Off
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_ON" desc="The label to indicate that a specific extension is currently enabled.">
-          On
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_OPTIONS" desc="The label on the button to open an extension options page.">
-          Extension options
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_PERMISSIONS" desc="The label above the list of an extension's permissions.">
-          Permissions
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_PERMISSIONS_EMPTY" desc="The text to indicate that an extension does not have any special permissions.">
-          This extension requires no special permissions.
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_REMOVE" desc="The label of the button to remove an extension.">
-          Remove
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_REMOVE_EXTENSION" desc="The label on the button to remove an extension.">
-          Remove extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE" desc="The label above an extension's source, which indicates where the extension came from (webstore, third-party, local disk, etc).">
-          Source
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_POLICY" desc="The text to indicate that an extension has been added by enterprise policy.">
-          Added by policy
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_SIDELOADED" desc="The text to indicate that an extension has been added by a third-party program on the user's machine.">
-          Added by a third-party
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_UNPACKED" desc="The text to indicate that an extension is loaded as an unpacked extension, as is done by developers.">
-          Unpacked extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_WEBSTORE" desc="The text to indicate that an extension is from the Chrome Web Store.">
-          Chrome Web Store
-        </message>
-        <message name="IDS_MD_EXTENSIONS_ITEM_VERSION" desc="The label above an extension's version.">
-          Version
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_HEADING" desc="The title of the dialog displaying the error when loading an unpacked extension fails.">
-          Failed to load extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_ERROR_LABEL" desc="The label next to the error of an unpacked extension that failed to load.">
-          Error
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_FILE_LABEL" desc="The label next to the file path of an unpacked extension that failed to load.">
-          File
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_COULD_NOT_LOAD_MANIFEST" desc="The text to indicate that an extension's manifest could not be loaded.">
-          Could not load manifest.
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_CANCEL" desc="The text on the button to close the dialog when an unpacked extension failed to load.">
-          Cancel
-        </message>
-        <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_RETRY" desc="The text on the button to retry loading an unpacked extension after a failed load.">
-          Retry
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_TITLE" desc="The title of the dialog to pack an extension.">
-          Pack extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_BROWSE_BUTTON" desc="The label of the button to browse the file system to select an extension directory or file.">
-          Browse
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_EXTENSION_ROOT_LABEL" desc="The label of the input field for specifying the root directory to pack an extension from.">
-          Extension root directory
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_KEY_FILE_LABEL" desc="The label of the input field for specifying the private key file for an extension being packed.">
-          Private key file (optional)
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_CONFIRM_BUTTON" desc="The label of the button to confirm the action to pack an extension.">
-          Pack extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_CANCEL_BUTTON" desc="The label of the button to cancel the pack extension dialog.">
-          Cancel
-        </message>
-        <message name="IDS_MD_EXTENSIONS_TOOLBAR_TITLE" desc="The text displayed in the toolbar of the chrome://extensions page.">
-          Extensions &amp; Apps
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SEARCH" desc="The text displayed in the search box on the chrome://extensions page.">
-          Search extensions
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SHORTCUT_NOT_SET" desc="The label to indicate that an extension has no shortcut set for a given command.">
-          Not set
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SHORTCUT_SCOPE_LABEL" desc="The label for the dropdown menu that lets the user choose the scope of an extension command (within chrome or global).">
-          Scope
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SHORTCUT_SCOPE_GLOBAL" desc="The label to indicate that a shortcut will be triggerable globally (including outside of the Chrome application).">
-          Global
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SIDEBAR_APPS" desc="The text displayed in the sidebar to go to the apps section of the page.">
-          Chrome Apps
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SIDEBAR_EXTENSIONS" desc="The text displayed in the sidebar to go to the extensions section of the page.">
-          Extensions
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SIDEBAR_GET_MORE_EXTENSIONS" desc="The text for the link to get more extensions in the extensions page.">
-          Get more extensions
-        </message>
-        <message name="IDS_MD_EXTENSIONS_SIDEBAR_KEYBOARD_SHORTCUTS" desc="The text for the link to manage keyboard shortcuts for extensions.">
-          Keyboard shortcuts
-        </message>
-        <message name="IDS_MD_EXTENSIONS_TOOLBAR_LOAD_UNPACKED" desc="The text displayed in the toolbar to load an unpacked extension.">
-          Load unpacked
-        </message>
-        <message name="IDS_MD_EXTENSIONS_TOOLBAR_PACK" desc="The text displayed in the toolbar to pack an extension directory.">
-          Pack extension
-        </message>
-        <message name="IDS_MD_EXTENSIONS_TOOLBAR_UPDATE_NOW" desc="The text displayed in the toolbar to update existing extensions now.">
-          Update
-        </message>
-        <message name="IDS_MD_EXTENSIONS_TYPE_A_SHORTCUT" desc="The prompt to the user to enter a keyboard shortcut in order to assign it to an extension.">
-          Type a shortcut
-        </message>
         <if expr="not use_titlecase">
           <message name="IDS_EXTENSIONS_CONTEXT_MENU_PAGE_ACCESS" desc="The label in an extension's context menu for the submenu specifying whether or not the extension can run on the current page (sentence case).">
             Page access
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
new file mode 100644
index 0000000..9e9c912
--- /dev/null
+++ b/chrome/app/md_extensions_strings.grdp
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- MD Extensions strings (included from generated_resources.grd). -->
+<grit-part>
+  <message name="IDS_MD_EXTENSIONS_DEVELOPER_MODE" desc="The text displayed next to the checkbox to toggle developer mode in the extensions page.">
+    Developer mode
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ERROR_PAGE_HEADING" desc="The heading of the page displaying an extension's errors.">
+    Errors
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_ERRORS" desc="The label of the button to bring the user to the page showing an extension's errors.">
+    Errors
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_ID" desc="The text for the label next to the extension id.">
+    &lt;span&gt;ID:&lt;/span&gt;<ph name="EXTENSION_ID">$1<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_INSPECT_VIEWS" desc="The text next to any inspectable views for an extension.">
+    Inspect views:
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_INSPECT_VIEWS_EXTRA" desc="The text to indicate there are additional inspectable views that aren't listed.">
+    <ph name="NUMBER_OF_VIEWS">$1<ex>2</ex></ph> more...
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_ALLOW_INCOGNITO" desc="The text next to the checkbox to enable an extension in incognito mode.">
+    Allow in incognito
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_DEPENDENCIES" desc="The label above a list of any extensions that depend on this extension.">
+    The following extensions depend on this extension:
+  </message>
+  <message name="IDS_MD_EXTENSIONS_DEPENDENT_ENTRY" desc="An item in the list of extensions that depend on this extension. 'NAME_PH' is the name of the extension that depends on this extension, and 'ID_PH' is the id of the extension that depends on this extension">
+    <ph name="NAME_PH">$1<ex>AdBlock</ex></ph> (ID: <ph name="ID_PH">$2<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>)
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_DESCRIPTION" desc="The label above the description for a given item.">
+    Description
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_DETAILS" desc="The text on the button to show more details for a given extension.">
+    Details
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_ID_HEADING" desc="The heading above the ID of the extension.">
+    ID
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_OFF" desc="The label to indicate that a specific extension is not currently enabled.">
+    Off
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_ON" desc="The label to indicate that a specific extension is currently enabled.">
+    On
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_OPTIONS" desc="The label on the button to open an extension options page.">
+    Extension options
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_PERMISSIONS" desc="The label above the list of an extension's permissions.">
+    Permissions
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_PERMISSIONS_EMPTY" desc="The text to indicate that an extension does not have any special permissions.">
+    This extension requires no special permissions.
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_REMOVE" desc="The label of the button to remove an extension.">
+    Remove
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_REMOVE_EXTENSION" desc="The label on the button to remove an extension.">
+    Remove extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE" desc="The label above an extension's source, which indicates where the extension came from (webstore, third-party, local disk, etc).">
+    Source
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_POLICY" desc="The text to indicate that an extension has been added by enterprise policy.">
+    Added by policy
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_SIDELOADED" desc="The text to indicate that an extension has been added by a third-party program on the user's machine.">
+    Added by a third-party
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_UNPACKED" desc="The text to indicate that an extension is loaded as an unpacked extension, as is done by developers.">
+    Unpacked extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_SOURCE_WEBSTORE" desc="The text to indicate that an extension is from the Chrome Web Store.">
+    Chrome Web Store
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ITEM_VERSION" desc="The label above an extension's version.">
+    Version
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_HEADING" desc="The title of the dialog displaying the error when loading an unpacked extension fails.">
+    Failed to load extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_ERROR_LABEL" desc="The label next to the error of an unpacked extension that failed to load.">
+    Error
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_FILE_LABEL" desc="The label next to the file path of an unpacked extension that failed to load.">
+    File
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_COULD_NOT_LOAD_MANIFEST" desc="The text to indicate that an extension's manifest could not be loaded.">
+    Could not load manifest.
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_CANCEL" desc="The text on the button to close the dialog when an unpacked extension failed to load.">
+    Cancel
+  </message>
+  <message name="IDS_MD_EXTENSIONS_LOAD_ERROR_RETRY" desc="The text on the button to retry loading an unpacked extension after a failed load.">
+    Retry
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_TITLE" desc="The title of the dialog to pack an extension.">
+    Pack extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_BROWSE_BUTTON" desc="The label of the button to browse the file system to select an extension directory or file.">
+    Browse
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_EXTENSION_ROOT_LABEL" desc="The label of the input field for specifying the root directory to pack an extension from.">
+    Extension root directory
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_KEY_FILE_LABEL" desc="The label of the input field for specifying the private key file for an extension being packed.">
+    Private key file (optional)
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_CONFIRM_BUTTON" desc="The label of the button to confirm the action to pack an extension.">
+    Pack extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_CANCEL_BUTTON" desc="The label of the button to cancel the pack extension dialog.">
+    Cancel
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TOOLBAR_TITLE" desc="The text displayed in the toolbar of the chrome://extensions page.">
+    Extensions &amp; Apps
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SEARCH" desc="The text displayed in the search box on the chrome://extensions page.">
+    Search extensions
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_NOT_SET" desc="The label to indicate that an extension has no shortcut set for a given command.">
+    Not set
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_SCOPE_LABEL" desc="The label for the dropdown menu that lets the user choose the scope of an extension command (within chrome or global).">
+    Scope
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_SCOPE_GLOBAL" desc="The label to indicate that a shortcut will be triggerable globally (including outside of the Chrome application).">
+    Global
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SIDEBAR_APPS" desc="The text displayed in the sidebar to go to the apps section of the page.">
+    Chrome Apps
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SIDEBAR_EXTENSIONS" desc="The text displayed in the sidebar to go to the extensions section of the page.">
+    Extensions
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SIDEBAR_GET_MORE_EXTENSIONS" desc="The text for the link to get more extensions in the extensions page.">
+    Get more extensions
+  </message>
+  <message name="IDS_MD_EXTENSIONS_SIDEBAR_KEYBOARD_SHORTCUTS" desc="The text for the link to manage keyboard shortcuts for extensions.">
+    Keyboard shortcuts
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TOOLBAR_LOAD_UNPACKED" desc="The text displayed in the toolbar to load an unpacked extension.">
+    Load unpacked
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TOOLBAR_PACK" desc="The text displayed in the toolbar to pack an extension directory.">
+    Pack extension
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TOOLBAR_UPDATE_NOW" desc="The text displayed in the toolbar to update existing extensions now.">
+    Update
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TYPE_A_SHORTCUT" desc="The prompt to the user to enter a keyboard shortcut in order to assign it to an extension.">
+    Type a shortcut
+  </message>
+</grit-part>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d2ad4bf2..36375b2e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1861,13 +1861,6 @@
      flag_descriptions::kUserConsentForExtensionScriptsDescription, kOsAll,
      SINGLE_VALUE_TYPE(extensions::switches::kEnableScriptsRequireAction)},
 #endif  // ENABLE_EXTENSIONS
-#if defined(OS_ANDROID)
-    {"enable-data-reduction-proxy-carrier-test",
-     flag_descriptions::kDataReductionProxyCarrierTestName,
-     flag_descriptions::kDataReductionProxyCarrierTestDescription, kOsAndroid,
-     SINGLE_VALUE_TYPE(
-         data_reduction_proxy::switches::kEnableDataReductionProxyCarrierTest)},
-#endif  // OS_ANDROID
     {"enable-hotword-hardware",
      flag_descriptions::kExperimentalHotwordHardwareName,
      flag_descriptions::kExperimentalHotwordHardwareDescription, kOsCrOS,
@@ -3150,6 +3143,13 @@
      FEATURE_VALUE_TYPE(search_provider_logos::features::kUseDdljsonApi)},
 #endif  // defined(OS_ANDROID)
 
+#if defined(OS_ANDROID)
+    {"spannable-inline-autocomplete",
+     flag_descriptions::kSpannableInlineAutocompleteName,
+     flag_descriptions::kSpannableInlineAutocompleteDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kSpannableInlineAutocomplete)},
+#endif  // defined(OS_ANDROID)
+
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms/enums.xml. See note in
     // enums.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 6f97fcb..7ef4fbad 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -53,6 +53,7 @@
     &kCCTBackgroundTab,
     &kCCTExternalLinkHandling,
     &kCCTPostMessageAPI,
+    &kCCTRedirectPreconnect,
     &kChromeHomeFeature,
     &kChromeHomeExpandButton,
     &kChromeHomeSwipeLogic,
@@ -82,6 +83,7 @@
     &kPhysicalWebSharing,
     &kSearchEnginePromoExistingDevice,
     &kSearchEnginePromoNewDevice,
+    &kSpannableInlineAutocomplete,
     &kSpecialLocaleFeature,
     &kSpecialLocaleWrapper,
     &kTabReparenting,
@@ -135,6 +137,9 @@
 const base::Feature kCCTPostMessageAPI{"CCTPostMessageAPI",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kCCTRedirectPreconnect{"CCTRedirectPreconnect",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kChromeHomeFeature{"ChromeHome",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -221,6 +226,9 @@
 const base::Feature kPhysicalWebSharing{"PhysicalWebSharing",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kSpannableInlineAutocomplete{
+    "SpannableInlineAutocomplete", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kSpecialLocaleFeature{"SpecialLocale",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 350b8c8..b893bce 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -19,6 +19,7 @@
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTExternalLinkHandling;
 extern const base::Feature kCCTPostMessageAPI;
+extern const base::Feature kCCTRedirectPreconnect;
 extern const base::Feature kChromeHomeFeature;
 extern const base::Feature kChromeHomeExpandButton;
 extern const base::Feature kChromeHomeSwipeLogic;
@@ -47,6 +48,7 @@
 extern const base::Feature kPayWithGoogleV1;
 extern const base::Feature kPhysicalWebFeature;
 extern const base::Feature kPhysicalWebSharing;
+extern const base::Feature kSpannableInlineAutocomplete;
 extern const base::Feature kSpecialLocaleFeature;
 extern const base::Feature kSpecialLocaleWrapper;
 extern const base::Feature kTabReparenting;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 8f55b28..5563c919 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -1557,13 +1557,15 @@
 }
 
 - (BOOL)application:(NSApplication*)application
-    willContinueUserActivityWithType:(NSString*)userActivityType {
+    willContinueUserActivityWithType:(NSString*)userActivityType
+    __attribute__((availability(macos, introduced = 10.10))) {
   return [userActivityType isEqualToString:NSUserActivityTypeBrowsingWeb];
 }
 
 - (BOOL)application:(NSApplication*)application
     continueUserActivity:(NSUserActivity*)userActivity
-      restorationHandler:(void (^)(NSArray*))restorationHandler {
+      restorationHandler:(void (^)(NSArray*))restorationHandler
+    __attribute__((availability(macos, introduced = 10.10))) {
   if (![userActivity.activityType
           isEqualToString:NSUserActivityTypeBrowsingWeb]) {
     return NO;
@@ -1599,7 +1601,14 @@
 }
 
 - (void)passURLToHandoffManager:(const GURL&)handoffURL {
-  [handoffManager_ updateActiveURL:handoffURL];
+  if (@available(macOS 10.10, *)) {
+    [handoffManager_ updateActiveURL:handoffURL];
+  } else {
+    // Only ends up being called in 10.10+, i.e. if shouldUseHandoff returns
+    // true. Some tests override shouldUseHandoff to always return true, but
+    // then they also override this function to do something else.
+    NOTREACHED();
+  }
 }
 
 - (void)updateHandoffManager:(content::WebContents*)webContents {
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 6b5e73b..eec47e0 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -698,14 +698,20 @@
     LoadAndLaunchPlatformApp("web_view/interstitial_teardown",
                              "EmbedderLoaded");
 
-    // Now load the guest.
+    // Create the guest.
     content::WebContents* embedder_web_contents =
         GetFirstAppWindowWebContents();
-    ExtensionTestMessageListener second("GuestAddedToDom", false);
+    ExtensionTestMessageListener guest_added("GuestAddedToDom", false);
+    EXPECT_TRUE(content::ExecuteScript(embedder_web_contents,
+                                       base::StringPrintf("createGuest();\n")));
+    ASSERT_TRUE(guest_added.WaitUntilSatisfied());
+
+    // Now load the guest.
+    ExtensionTestMessageListener guest_loaded("GuestLoaded", false);
     EXPECT_TRUE(content::ExecuteScript(
         embedder_web_contents,
         base::StringPrintf("loadGuest(%d);\n", host_and_port.port())));
-    ASSERT_TRUE(second.WaitUntilSatisfied());
+    ASSERT_TRUE(guest_loaded.WaitUntilSatisfied());
 
     // Wait for interstitial page to be shown in guest.
     content::WebContents* guest_web_contents =
@@ -1788,6 +1794,23 @@
             content::GetFocusedRenderWidgetHost(outer_web_contents));
 }
 
+// Test makes sure that the browser does not crash when a <webview> navigates
+// out of an interstitial.
+IN_PROC_BROWSER_TEST_P(WebViewTest, InterstitialPageDetach) {
+  InterstitialTestHelper();
+
+  content::WebContents* guest_web_contents =
+      GetGuestViewManager()->WaitForSingleGuestCreated();
+  EXPECT_TRUE(guest_web_contents->ShowingInterstitialPage());
+
+  // Navigate to about:blank.
+  content::TestNavigationObserver load_observer(guest_web_contents);
+  bool result = ExecuteScript(guest_web_contents,
+                              "window.location.assign('about:blank')");
+  EXPECT_TRUE(result);
+  load_observer.Wait();
+}
+
 // This test makes sure the browser process does not crash if app is closed
 // while an interstitial page is being shown in guest.
 IN_PROC_BROWSER_TEST_P(WebViewTest, InterstitialTeardown) {
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index aaa3649..204a64a 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -42,6 +42,7 @@
 #include "jni/PersonalDataManager_jni.h"
 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace autofill {
 namespace {
@@ -310,10 +311,12 @@
 };
 
 void OnSubKeysReceived(ScopedJavaGlobalRef<jobject> jdelegate,
-                       const std::vector<std::string>& sub_keys) {
+                       const std::vector<std::string>& subkeys_codes,
+                       const std::vector<std::string>& subkeys_names) {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_GetSubKeysRequestDelegate_onSubKeysReceived(
-      env, jdelegate, base::android::ToJavaArrayOfStrings(env, sub_keys));
+      env, jdelegate, base::android::ToJavaArrayOfStrings(env, subkeys_codes),
+      base::android::ToJavaArrayOfStrings(env, subkeys_names));
 }
 
 }  // namespace
@@ -776,8 +779,10 @@
   ::payments::SubKeyReceiverCallback cb = base::BindOnce(
       &OnSubKeysReceived, ScopedJavaGlobalRef<jobject>(my_jdelegate));
 
-  subkey_requester_.StartRegionSubKeysRequest(region_code, jtimeout_seconds,
-                                              std::move(cb));
+  std::string language =
+      l10n_util::GetLanguage(g_browser_process->GetApplicationLocale());
+  subkey_requester_.StartRegionSubKeysRequest(region_code, language,
+                                              jtimeout_seconds, std::move(cb));
 }
 
 void PersonalDataManagerAndroid::CancelPendingGetSubKeys(
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index d151972..44b3367e 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -69,8 +70,7 @@
 static const char kTestFormString[] =
     "<form action=\"http://www.example.com/\" method=\"POST\">"
     "<label for=\"firstname\">First name:</label>"
-    " <input type=\"text\" id=\"firstname\""
-    "        onfocus=\"domAutomationController.send(true)\"><br>"
+    " <input type=\"text\" id=\"firstname\"><br>"
     "<label for=\"lastname\">Last name:</label>"
     " <input type=\"text\" id=\"lastname\"><br>"
     "<label for=\"address1\">Address line 1:</label>"
@@ -120,8 +120,7 @@
     "</script>"
     "<form action=\"http://www.example.com/\" method=\"POST\">"
     "<label for=\"firstname\">First name:</label>"
-    " <input type=\"text\" id=\"firstname\""
-    "        onfocus=\"domAutomationController.send(true)\"><br>"
+    " <input type=\"text\" id=\"firstname\"><br>"
     "<label for=\"lastname\">Last name:</label>"
     " <input type=\"text\" id=\"lastname\""
     " onfocus=\"inputfocus = true\" onkeydown=\"inputkeydown = true\""
@@ -359,27 +358,25 @@
 
   void FocusFieldByName(const std::string& name) {
     bool result = false;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        GetRenderViewHost(),
-        "if (document.readyState === 'complete')"
-        "  document.getElementById('" + name + "').focus();"
-        "else"
-        "  domAutomationController.send(false);",
-        &result));
+    std::string script = base::StringPrintf(
+        R"( function onFocusHandler(e) {
+              e.target.removeEventListener(e.type, arguments.callee);
+              domAutomationController.send(true);
+            }
+            if (document.readyState === 'complete') {
+              var target = document.getElementById('%s');
+              target.addEventListener('focus', onFocusHandler);
+              target.focus();
+            } else {
+              domAutomationController.send(false);
+            })",
+        name.c_str());
+    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetRenderViewHost(),
+                                                     script, &result));
     ASSERT_TRUE(result);
   }
 
-  void FocusFirstNameField() {
-    bool result = false;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        GetRenderViewHost(),
-        "if (document.readyState === 'complete')"
-        "  document.getElementById('firstname').focus();"
-        "else"
-        "  domAutomationController.send(false);",
-        &result));
-    ASSERT_TRUE(result);
-  }
+  void FocusFirstNameField() { FocusFieldByName("firstname"); }
 
   // Simulates a click on the middle of the DOM element with the given |id|.
   void ClickElementWithId(const std::string& id) {
@@ -795,8 +792,7 @@
       browser(),
       GURL(std::string(kDataURIPrefix) +
            "<form action=\"http://www.example.com/\" method=\"POST\">"
-           "  <input list=\"dl\" type=\"search\" id=\"firstname\""
-           "         onfocus=\"domAutomationController.send(true)\"><br>"
+           "  <input list=\"dl\" type=\"search\" id=\"firstname\"><br>"
            "  <datalist id=\"dl\">"
            "  <option value=\"Adam\"></option>"
            "  <option value=\"Bob\"></option>"
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 09296267..37e4924c 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -37,6 +38,7 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -893,6 +895,48 @@
   transport_security_state->AddHSTS(host, expiry, include_subdomains);
 }
 
+// Helper for waiting for a change of the active tab.
+// Users can wait for the change via WaitForActiveTabChange method.
+// DCHECKs ensure that only one change happens during the lifetime of a
+// TabActivationWaiter instance.
+class TabActivationWaiter : public TabStripModelObserver {
+ public:
+  explicit TabActivationWaiter(TabStripModel* tab_strip_model)
+      : number_of_unconsumed_active_tab_changes_(0), scoped_observer_(this) {
+    scoped_observer_.Add(tab_strip_model);
+  }
+
+  void WaitForActiveTabChange() {
+    if (number_of_unconsumed_active_tab_changes_ == 0) {
+      // Wait until TabStripModelObserver::ActiveTabChanged will get called.
+      message_loop_runner_ = new content::MessageLoopRunner;
+      message_loop_runner_->Run();
+    }
+
+    // "consume" one tab activation event.
+    DCHECK_EQ(1, number_of_unconsumed_active_tab_changes_);
+    number_of_unconsumed_active_tab_changes_--;
+  }
+
+  // TabStripModelObserver overrides.
+  void ActiveTabChanged(content::WebContents* old_contents,
+                        content::WebContents* new_contents,
+                        int index,
+                        int reason) override {
+    number_of_unconsumed_active_tab_changes_++;
+    DCHECK_EQ(1, number_of_unconsumed_active_tab_changes_);
+    if (message_loop_runner_)
+      message_loop_runner_->Quit();
+  }
+
+ private:
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  int number_of_unconsumed_active_tab_changes_;
+  ScopedObserver<TabStripModel, TabActivationWaiter> scoped_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabActivationWaiter);
+};
+
 }  // namespace
 
 class CaptivePortalBrowserTest : public InProcessBrowserTest {
@@ -1536,8 +1580,8 @@
   ASSERT_TRUE(IsLoginTab(browser->tab_strip_model()->GetActiveWebContents()));
 
   // Do the navigation.
-  EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
-                                     "submitForm()"));
+  content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
+                              "submitForm()");
 
   portal_observer.WaitForResults(1);
   navigation_observer.WaitForNavigations(1);
@@ -1582,8 +1626,8 @@
   ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
 
   // Trigger a navigation.
-  EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
-                                     "submitForm()"));
+  content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
+                              "submitForm()");
 
   portal_observer.WaitForResults(1);
 
@@ -1624,8 +1668,8 @@
   ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
 
   // Trigger a navigation.
-  EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
-                                     "submitForm()"));
+  content::ExecuteScriptAsync(tab_strip_model->GetActiveWebContents(),
+                              "submitForm()");
 
   // The captive portal tab navigation will trigger a captive portal check,
   // and reloading the original tab will bring up the interstitial page again,
@@ -1977,8 +2021,11 @@
   EXPECT_TRUE(WaitForRenderFrameReady(rfh));
   const char kClickConnectButtonJS[] =
       "document.getElementById('primary-button').click();";
-  EXPECT_TRUE(
-      content::ExecuteScript(rfh, kClickConnectButtonJS));
+  {
+    TabActivationWaiter tab_activation_waiter(tab_strip_model);
+    content::ExecuteScriptAsync(rfh, kClickConnectButtonJS);
+    tab_activation_waiter.WaitForActiveTabChange();
+  }
   EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
 
   // For completeness, close the login tab and try clicking |Connect| again.
@@ -1990,8 +2037,7 @@
       tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
   destroyed_watcher.Wait();
   MultiNavigationObserver navigation_observer;
-  EXPECT_TRUE(
-      content::ExecuteScript(rfh, kClickConnectButtonJS));
+  content::ExecuteScriptAsync(rfh, kClickConnectButtonJS);
   navigation_observer.WaitForNavigations(1);
   EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
 
diff --git a/chrome/browser/chrome_site_per_process_browsertest.cc b/chrome/browser/chrome_site_per_process_browsertest.cc
index 30a5550a..c7fb95c 100644
--- a/chrome/browser/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/chrome_site_per_process_browsertest.cc
@@ -264,7 +264,7 @@
 
   // Focus the popup via window.focus().
   content::DOMMessageQueue queue;
-  EXPECT_TRUE(ExecuteScript(web_contents, "focusPopup()"));
+  ExecuteScriptAsync(web_contents, "focusPopup()");
 
   // Wait for main page to lose focus and for popup to gain focus.  Each event
   // will send a message, and the two messages can arrive in any order.
diff --git a/chrome/browser/chromeos/base/file_flusher_unittest.cc b/chrome/browser/chromeos/base/file_flusher_unittest.cc
index 361d489..b646aab 100644
--- a/chrome/browser/chromeos/base/file_flusher_unittest.cc
+++ b/chrome/browser/chromeos/base/file_flusher_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -57,11 +56,6 @@
     }
   }
 
-  void TearDown() override {
-    content::BrowserThread::GetBlockingPool()->FlushForTesting();
-    base::RunLoop().RunUntilIdle();
-  }
-
   std::unique_ptr<FileFlusher> CreateFileFlusher() {
     std::unique_ptr<FileFlusher> flusher(new FileFlusher);
     flusher->set_on_flush_callback_for_test(
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index cc2e865..fbdd0b8 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/common/service_manager_connection.h"
@@ -54,6 +55,7 @@
       app_window_observer_(this),
       session_observer_(this),
       input_devices_observer_(this),
+      power_manager_client_observer_(this),
       weak_ptr_factory_(this) {
   DCHECK(!g_instance);
   DCHECK(IsEnabled());
@@ -138,6 +140,8 @@
                            lock_screen_profile->GetOriginalProfile());
 
   input_devices_observer_.Add(ui::InputDeviceManager::GetInstance());
+  power_manager_client_observer_.Add(
+      chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
   session_observer_.Add(session_manager::SessionManager::Get());
   OnSessionStateChanged();
 
@@ -176,7 +180,7 @@
 void StateController::OnSessionStateChanged() {
   if (!session_manager::SessionManager::Get()->IsScreenLocked()) {
     app_manager_->Stop();
-    ResetNoteTakingWindowAndMoveToNextState(true /* close_window */);
+    ResetNoteTakingWindowAndMoveToNextState(true /*close_window*/);
     return;
   }
 
@@ -192,7 +196,7 @@
 void StateController::OnAppWindowRemoved(extensions::AppWindow* app_window) {
   if (note_app_window_ != app_window)
     return;
-  ResetNoteTakingWindowAndMoveToNextState(false /* close_window */);
+  ResetNoteTakingWindowAndMoveToNextState(false /*close_window*/);
 }
 
 void StateController::OnStylusStateChanged(ui::StylusState state) {
@@ -203,6 +207,15 @@
     RequestNewLockScreenNote();
 }
 
+void StateController::BrightnessChanged(int level, bool user_initiated) {
+  if (level == 0 && !user_initiated)
+    ResetNoteTakingWindowAndMoveToNextState(true /*close_window*/);
+}
+
+void StateController::SuspendImminent() {
+  ResetNoteTakingWindowAndMoveToNextState(true /*close_window*/);
+}
+
 extensions::AppWindow* StateController::CreateAppWindowForLockScreenAction(
     content::BrowserContext* context,
     const extensions::Extension* extension,
@@ -247,7 +260,7 @@
   if (!app_manager_->IsNoteTakingAppAvailable() ||
       (note_app_window_ && note_app_window_->GetExtension()->id() !=
                                app_manager_->GetNoteTakingAppId())) {
-    ResetNoteTakingWindowAndMoveToNextState(true /* close_window */);
+    ResetNoteTakingWindowAndMoveToNextState(true /*close_window*/);
     return;
   }
 
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index 2db94ca..ee98d89 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chromeos/dbus/power_manager_client.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/api/app_runtime.h"
@@ -48,7 +49,8 @@
 class StateController : public ash::mojom::TrayActionClient,
                         public session_manager::SessionManagerObserver,
                         public extensions::AppWindowRegistry::Observer,
-                        public ui::InputDeviceEventObserver {
+                        public ui::InputDeviceEventObserver,
+                        public chromeos::PowerManagerClient::Observer {
  public:
   // Returns whether the StateController is enabled - it is currently guarded by
   // a feature flag. If not enabled, |StateController| instance is not allowed
@@ -99,6 +101,10 @@
   // ui::InputDeviceEventObserver:
   void OnStylusStateChanged(ui::StylusState state) override;
 
+  // chromeos::PowerManagerClient::Observer
+  void BrightnessChanged(int level, bool user_initiated) override;
+  void SuspendImminent() override;
+
   // Creates and registers an app window as action handler for the action on
   // Chrome OS lock screen. The ownership of the returned app window is passed
   // to the caller.
@@ -167,6 +173,9 @@
       session_observer_;
   ScopedObserver<ui::InputDeviceManager, ui::InputDeviceEventObserver>
       input_devices_observer_;
+  ScopedObserver<chromeos::PowerManagerClient,
+                 chromeos::PowerManagerClient::Observer>
+      power_manager_client_observer_;
 
   // If set, this callback will be run when the state controller is fully
   // initialized. It can be used to throttle tests until state controller
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 989b027..97d46203 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
@@ -24,6 +24,8 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_power_manager_client.h"
 #include "components/session_manager/core/session_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -325,6 +327,12 @@
 
     ASSERT_TRUE(profile_manager_.SetUp());
 
+    auto power_client = base::MakeUnique<chromeos::FakePowerManagerClient>();
+    power_manager_client_ = power_client.get();
+    std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter =
+        chromeos::DBusThreadManager::GetSetterForTesting();
+    dbus_setter->SetPowerManagerClient(std::move(power_client));
+
     BrowserWithTestWindowTest::SetUp();
 
     session_manager_ = base::MakeUnique<session_manager::SessionManager>();
@@ -473,6 +481,10 @@
   TestingProfile* profile() { return &profile_; }
   TestingProfile* lock_screen_profile() { return lock_screen_profile_; }
 
+  chromeos::FakePowerManagerClient* power_manager_client() {
+    return power_manager_client_;
+  }
+
   session_manager::SessionManager* session_manager() {
     return session_manager_.get();
   }
@@ -505,6 +517,10 @@
   // controller.
   base::RunLoop ready_waiter_;
 
+  // Power manager client set by the test - the power manager client instance is
+  // owned by DBusThreadManager.
+  chromeos::FakePowerManagerClient* power_manager_client_ = nullptr;
+
   std::unique_ptr<session_manager::SessionManager> session_manager_;
 
   std::unique_ptr<lock_screen_apps::StateController> state_controller_;
@@ -944,6 +960,51 @@
   EXPECT_TRUE(app_window()->closed());
 }
 
+TEST_F(LockScreenAppStateTest, CloseAppWindowOnSuspend) {
+  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
+                                      true /* enable_app_launch */));
+
+  power_manager_client()->SendSuspendImminent();
+  EXPECT_EQ(TrayActionState::kAvailable,
+            state_controller()->GetLockScreenNoteState());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(app_window()->closed());
+}
+
+TEST_F(LockScreenAppStateTest, CloseAppWindowOnScreenOff) {
+  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
+                                      true /* enable_app_launch */));
+
+  power_manager_client()->SendBrightnessChanged(10 /* level */,
+                                                true /* user_initiated */);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(app_window()->closed());
+  EXPECT_EQ(TrayActionState::kActive,
+            state_controller()->GetLockScreenNoteState());
+
+  power_manager_client()->SendBrightnessChanged(0 /* level */,
+                                                true /* user_initiated */);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(app_window()->closed());
+  EXPECT_EQ(TrayActionState::kActive,
+            state_controller()->GetLockScreenNoteState());
+
+  power_manager_client()->SendBrightnessChanged(10 /* level */,
+                                                false /* user_initiated */);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(app_window()->closed());
+  EXPECT_EQ(TrayActionState::kActive,
+            state_controller()->GetLockScreenNoteState());
+
+  power_manager_client()->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/proxy_auth_dialog_browsertest.cc b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
index 65aa817d..d6c573c 100644
--- a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
+++ b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
@@ -119,9 +119,7 @@
     OobeScreenWaiter screen_waiter(OobeScreen::SCREEN_GAIA_SIGNIN);
     ProxyAuthDialogWaiter auth_dialog_waiter;
     ASSERT_TRUE(content::ExecuteScript(oobe_ui->web_ui()->GetWebContents(),
-                                       "window.domAutomationController.send(!!("
-                                       "$('add-user-button').click()"
-                                       "));"));
+                                       "$('add-user-button').click()"));
     screen_waiter.Wait();
     auth_dialog_waiter.Wait();
     ASSERT_TRUE(auth_dialog_waiter.login_handler());
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index c05eba90..a63586f 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -358,16 +358,16 @@
   }
 
   void SetupAuthFlowChangeListener() {
-    ASSERT_TRUE(content::ExecuteScript(
+    content::ExecuteScriptAsync(
         GetLoginUI()->GetWebContents(),
         "$('gaia-signin').gaiaAuthHost_.addEventListener('authFlowChange',"
-            "function f() {"
-              "$('gaia-signin').gaiaAuthHost_.removeEventListener("
-                  "'authFlowChange', f);"
-              "window.domAutomationController.setAutomationId(0);"
-              "window.domAutomationController.send("
-                  "$('gaia-signin').isSAML() ? 'SamlLoaded' : 'GaiaLoaded');"
-            "});"));
+        "    function f() {"
+        "      $('gaia-signin').gaiaAuthHost_.removeEventListener("
+        "          'authFlowChange', f);"
+        "      window.domAutomationController.setAutomationId(0);"
+        "      window.domAutomationController.send("
+        "          $('gaia-signin').isSAML() ? 'SamlLoaded' : 'GaiaLoaded');"
+        "    });");
   }
 
   virtual void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) {
@@ -463,9 +463,8 @@
 
   // Click on 'cancel'.
   content::DOMMessageQueue message_queue;  // Observe before 'cancel'.
-  ASSERT_TRUE(
-      content::ExecuteScript(GetLoginUI()->GetWebContents(),
-                             "$('gaia-navigation').$.closeButton.click();"));
+  content::ExecuteScriptAsync(GetLoginUI()->GetWebContents(),
+                              "$('gaia-navigation').$.closeButton.click();");
 
   // Auth flow should change back to Gaia.
   std::string message;
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 4d1c9e3..156c740 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -275,10 +275,8 @@
       run_loop.Run();
   }
 
-  bool JSExecute(const std::string& expression) {
-    return content::ExecuteScript(
-        GetWebContents(),
-        "window.domAutomationController.send(!!(" + expression + "));");
+  bool JSExecute(const std::string& script) {
+    return content::ExecuteScript(GetWebContents(), script);
   }
 
   bool JSExecuteBooleanExpression(const std::string& expression) {
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 2b2ba4a0..cb8821c 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/ui/ash/ash_util.h"
+#include "chrome/browser/ui/ash/system_tray_client.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
@@ -516,6 +517,7 @@
       tracing_manager_ = TracingManager::Create();
     else
       tracing_manager_.reset();
+    SystemTrayClient::Get()->SetPerformanceTracingIconVisible(enabled);
   }
   if (reason != REASON_PREF_CHANGED || pref_name == prefs::kTapToClickEnabled) {
     const bool enabled = tap_to_click_enabled_.GetValue();
diff --git a/chrome/browser/chromeos/printing/usb_printer_util.cc b/chrome/browser/chromeos/printing/usb_printer_util.cc
index 28ae5c1..5ba38bb5 100644
--- a/chrome/browser/chromeos/printing/usb_printer_util.cc
+++ b/chrome/browser/chromeos/printing/usb_printer_util.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/printing/printer_configuration.h"
@@ -146,8 +147,7 @@
 // from arbitrary devices.
 std::unique_ptr<Printer> UsbDeviceToPrinter(const device::UsbDevice& device) {
   // Preflight all required fields and log errors if we find something wrong.
-  if (device.vendor_id() == 0 || device.product_id() == 0 ||
-      device.manufacturer_string().empty() || device.product_string().empty()) {
+  if (device.vendor_id() == 0 || device.product_id() == 0) {
     LOG(ERROR) << "Failed to convert USB device to printer.  Fields were:\n"
                << UsbPrinterDeviceDetailsAsString(device);
     return nullptr;
@@ -156,9 +156,23 @@
   auto printer = base::MakeUnique<Printer>();
   printer->set_manufacturer(base::UTF16ToUTF8(device.manufacturer_string()));
   printer->set_model(base::UTF16ToUTF8(device.product_string()));
-  printer->set_display_name(base::StringPrintf("%s %s (USB)",
-                                               printer->manufacturer().c_str(),
-                                               printer->model().c_str()));
+
+  // Construct the display name by however much of the manufacturer/model
+  // information that we have available.
+  std::vector<std::string> display_name_parts;
+  if (!printer->manufacturer().empty()) {
+    display_name_parts.push_back(printer->manufacturer());
+  }
+  if (!printer->model().empty()) {
+    display_name_parts.push_back(printer->model());
+  }
+  if (display_name_parts.empty()) {
+    // If we have neither manufacturer nor model, just display the name as
+    // unknown.
+    display_name_parts.push_back("Unknown Printer");
+  }
+  display_name_parts.push_back("(USB)");
+  printer->set_display_name(base::JoinString(display_name_parts, " "));
   printer->set_description(printer->display_name());
   printer->set_uri(UsbPrinterUri(device));
   printer->set_id(UsbPrinterId(device));
diff --git a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
index fd1a0ac..5337a4c 100644
--- a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
+++ b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
@@ -5,10 +5,9 @@
 #include "chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h"
 
 #include "ash/multi_profile_uma.h"
-#include "ash/shell.h"
-#include "ash/system/tray/system_tray_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
+#include "chrome/browser/ui/ash/session_controller_client.h"
 #include "chrome/browser/ui/browser.h"
 #include "components/user_manager/user_manager.h"
 
@@ -29,7 +28,7 @@
   // Let the user add another account to the session.
   ash::MultiProfileUMA::RecordSigninUser(
       ash::MultiProfileUMA::SIGNIN_USER_BY_BROWSER_FRAME);
-  ash::Shell::Get()->system_tray_delegate()->ShowUserLogin();
+  SessionControllerClient::Get()->ShowMultiProfileLogin();
 }
 
 void AvatarMenuActionsChromeOS::EditProfile(Profile* profile) {
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_x11.cc b/chrome/browser/chromeos/system/input_device_settings_impl_x11.cc
index 59a83f8..3908d06 100644
--- a/chrome/browser/chromeos/system/input_device_settings_impl_x11.cc
+++ b/chrome/browser/chromeos/system/input_device_settings_impl_x11.cc
@@ -22,7 +22,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
 #include "base/task_runner.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "content/public/browser/browser_thread.h"
@@ -84,11 +84,10 @@
   // Control scripts can take long enough to cause SIGART during shutdown
   // (http://crbug.com/261426). Run the blocking pool task with
   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
-  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-  scoped_refptr<base::TaskRunner> runner =
-      pool->GetTaskRunnerWithShutdownBehavior(
-          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-  runner->PostTask(FROM_HERE, base::Bind(&ExecuteScriptOnFileThread, argv));
+  base::PostTaskWithTraits(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&ExecuteScriptOnFileThread, argv));
 }
 
 void AddSensitivityArguments(const char* device_type,
@@ -138,12 +137,10 @@
   // (http://crbug.com/255546). Run the blocking pool task with
   // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down.
   scoped_refptr<RefCountedBool> exists(new RefCountedBool(false));
-  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-  scoped_refptr<base::TaskRunner> runner =
-      pool->GetTaskRunnerWithShutdownBehavior(
-          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-  runner->PostTaskAndReply(
-      FROM_HERE, base::Bind(&DeviceExistsBlockingPool, script, exists),
+  base::PostTaskWithTraitsAndReply(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&DeviceExistsBlockingPool, script, exists),
       base::BindOnce(&RunCallbackUIThread, exists, std::move(callback)));
 }
 
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index cbbefdc..581839d 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -12,6 +12,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -188,9 +189,16 @@
 // not accessing any global browser state while the code is running.
 scoped_refptr<base::SequencedTaskRunner>
 ChromeConfigurator::GetSequencedTaskRunner() const {
-  return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::BACKGROUND,
-       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+  constexpr base::TaskTraits traits = {
+      base::MayBlock(), base::TaskPriority::BACKGROUND,
+      base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
+#if defined(OS_WIN)
+  // Use the COM STA task runner as the Windows background downloader requires
+  // COM initialization.
+  return base::CreateCOMSTATaskRunnerWithTraits(traits);
+#else
+  return base::CreateSequencedTaskRunnerWithTraits(traits);
+#endif
 }
 
 PrefService* ChromeConfigurator::GetPrefService() const {
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc
index e9b382b..5f44f9e1 100644
--- a/chrome/browser/extensions/browsertest_util.cc
+++ b/chrome/browser/extensions/browsertest_util.cc
@@ -51,7 +51,8 @@
     ADD_FAILURE() << "Extension " << extension_id << " has no background page.";
     return false;
   }
-  return content::ExecuteScript(host->host_contents(), script);
+  content::ExecuteScriptAsync(host->host_contents(), script);
+  return true;
 }
 
 void CreateAndInitializeLocalCache() {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 672ffc3..8301b810 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -117,11 +117,6 @@
     "Highly experimental where guests such as &lt;webview> are implemented on "
     "the out-of-process iframe infrastructure.";
 
-const char kDataReductionProxyCarrierTestName[] =
-    "Enable a carrier-specific Data Reduction Proxy for testing.";
-const char kDataReductionProxyCarrierTestDescription[] =
-    "Use a carrier-specific Data Reduction Proxy for testing.";
-
 const char kDataReductionProxyLoFiName[] = "Data Saver Lo-Fi mode";
 const char kDataReductionProxyLoFiDescription[] =
     "Forces Data Saver Lo-Fi mode to be always enabled, enabled only on "
@@ -3146,4 +3141,13 @@
 
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_ANDROID)
+
+const char kSpannableInlineAutocompleteName[] = "Spannable inline autocomplete";
+const char kSpannableInlineAutocompleteDescription[] =
+    "A new type of inline autocomplete for the omnibox that works with "
+    "keyboards that compose text.";
+
+#endif  // defined(OS_ANDROID)
+
 }  // namespace flag_descriptions
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 5b3fd7b..ec99aa9 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -93,9 +93,6 @@
 extern const char kCrossProcessGuestViewIsolationName[];
 extern const char kCrossProcessGuestViewIsolationDescription[];
 
-extern const char kDataReductionProxyCarrierTestName[];
-extern const char kDataReductionProxyCarrierTestDescription[];
-
 extern const char kDataReductionProxyLoFiName[];
 extern const char kDataReductionProxyLoFiDescription[];
 extern const char kDataReductionProxyLoFiAlwaysOn[];
@@ -1114,6 +1111,9 @@
 extern const char kSetMarketUrlForTestingName[];
 extern const char kSetMarketUrlForTestingDescription[];
 
+extern const char kSpannableInlineAutocompleteName[];
+extern const char kSpannableInlineAutocompleteDescription[];
+
 extern const char kTabsInCbdName[];
 extern const char kTabsInCbdDescription[];
 
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index 34efb8e6..5c40e9e4 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -413,19 +413,16 @@
 
 bool GeolocationBrowserTest::SetPositionAndWaitUntilUpdated(double latitude,
                                                             double longitude) {
+  content::DOMMessageQueue dom_message_queue;
+
   fake_latitude_ = latitude;
   fake_longitude_ = longitude;
   ui_test_utils::OverrideGeolocation(latitude, longitude);
 
-  // Now wait until the new position gets to the script.
-  // Control will return (a) if the update has already been received, or (b)
-  // when the update is received. This will hang if the position is never
-  // updated. Currently this expects the position to be updated once; if your
-  // test updates it repeatedly, |position_updated| (JS) needs to change to an
-  // int to count how often it's been updated.
-  std::string result =
-      RunScript(render_frame_host_, "checkIfGeopositionUpdated()");
-  return result == "geoposition-updated";
+  std::string result;
+  if (!dom_message_queue.WaitForMessage(&result))
+    return false;
+  return result == "\"geoposition-updated\"";
 }
 
 int GeolocationBrowserTest::GetRequestQueueSize(
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 8b64aa7..4d7bb35 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -298,8 +298,13 @@
                         media::kClearKeyCdmPepperMimeType);
       if (cdm_host_type == CdmHostType::kMojo) {
         scoped_feature_list_.InitWithFeatures(
-            {media::kExternalClearKeyForTesting, media::kMojoCdm}, {});
+            {media::kExternalClearKeyForTesting, media::kMojoCdm,
+             media::kSupportExperimentalCdmInterface},
+            {});
       } else {
+        // Pepper CDMs are conditionally compiled with or without support for
+        // experimental CDMs, so media::kSupportExperimentalCdmInterface is
+        // not needed as it isn't checked.
         scoped_feature_list_.InitWithFeatures(
             {media::kExternalClearKeyForTesting}, {});
       }
diff --git a/chrome/browser/media/router/discovery/BUILD.gn b/chrome/browser/media/router/discovery/BUILD.gn
index 79ad9c1..75af5dad 100644
--- a/chrome/browser/media/router/discovery/BUILD.gn
+++ b/chrome/browser/media/router/discovery/BUILD.gn
@@ -62,6 +62,11 @@
     ]
   }
 
+  if (is_win) {
+    libs = [ "wlanapi.lib" ]
+    ldflags = [ "/DELAYLOAD:wlanapi.dll" ]
+  }
+
   if (is_mac) {
     libs = [ "CoreWLAN.framework" ]
   }
diff --git a/chrome/browser/media/router/discovery/discovery_network_list_win.cc b/chrome/browser/media/router/discovery/discovery_network_list_win.cc
index a18dd90..3bd7b2b 100644
--- a/chrome/browser/media/router/discovery/discovery_network_list_win.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_list_win.cc
@@ -4,7 +4,243 @@
 
 #include "chrome/browser/media/router/discovery/discovery_network_list.h"
 
-// TODO(btolsch): Implement this for Windows.
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <iphlpapi.h>  // NOLINT
+
+#include <windot11.h>  // NOLINT
+#include <wlanapi.h>   // NOLINT
+
+#include <algorithm>
+#include <cstring>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/containers/small_map.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace {
+
+struct GuidOperatorLess {
+  bool operator()(const GUID& guid1, const GUID& guid2) const {
+    return memcmp(&guid1, &guid2, sizeof(GUID)) < 0;
+  }
+};
+
+void IfTable2Deleter(PMIB_IF_TABLE2 interface_table) {
+  if (interface_table) {
+    FreeMibTable(interface_table);
+  }
+}
+
+void WlanApiDeleter(void* p) {
+  if (p) {
+    WlanFreeMemory(p);
+  }
+}
+
+class ScopedWlanClientHandle {
+ public:
+  ScopedWlanClientHandle() {}
+  ~ScopedWlanClientHandle() {
+    if (handle != nullptr) {
+      WlanCloseHandle(handle, nullptr);
+    }
+  }
+
+  HANDLE handle = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedWlanClientHandle);
+};
+
+// Returns a map from a network interface's GUID to its MAC address.  This
+// enumerates all network interfaces, not just wireless interfaces.
+base::small_map<std::map<GUID, std::string, GuidOperatorLess>>
+GetInterfaceGuidMacMap() {
+  PMIB_IF_TABLE2 interface_table_raw = nullptr;
+  auto result = GetIfTable2(&interface_table_raw);
+  if (result != ERROR_SUCCESS) {
+    LOG(WARNING) << "GetIfTable2() failed: " << result;
+    return {};
+  }
+  std::unique_ptr<MIB_IF_TABLE2, decltype(&IfTable2Deleter)> interface_table(
+      interface_table_raw, IfTable2Deleter);
+
+  base::small_map<std::map<GUID, std::string, GuidOperatorLess>> guid_mac_map;
+  for (ULONG i = 0; i < interface_table->NumEntries; ++i) {
+    const auto* interface_row = &interface_table->Table[i];
+    guid_mac_map.insert(std::make_pair(
+        interface_row->InterfaceGuid,
+        std::string{
+            reinterpret_cast<const char*>(interface_row->PhysicalAddress),
+            interface_row->PhysicalAddressLength}));
+  }
+
+  return guid_mac_map;
+}
+
+// Returns the associated SSID of an interface identified by its interface GUID.
+// If it is not a wireless interface or if it's not currently associated with a
+// network, it returns an empty string.
+std::string GetSsidForInterfaceGuid(const HANDLE wlan_client_handle,
+                                    const GUID& interface_guid) {
+  WLAN_CONNECTION_ATTRIBUTES* connection_info_raw = nullptr;
+  DWORD connection_info_size = 0;
+  auto result = WlanQueryInterface(
+      wlan_client_handle, &interface_guid, wlan_intf_opcode_current_connection,
+      nullptr, &connection_info_size,
+      reinterpret_cast<void**>(&connection_info_raw), nullptr);
+  if (result != ERROR_SUCCESS) {
+    // We can't get the SSID for this interface so its network ID will
+    // fall back to its MAC address below.
+    DVLOG(2) << "Failed to get wireless connection info: " << result;
+    return {};
+  }
+  std::unique_ptr<WLAN_CONNECTION_ATTRIBUTES, decltype(&WlanApiDeleter)>
+      connection_info(connection_info_raw, WlanApiDeleter);
+  if (connection_info->isState != wlan_interface_state_connected) {
+    return {};
+  }
+  const auto* ssid = &connection_info->wlanAssociationAttributes.dot11Ssid;
+  return std::string(reinterpret_cast<const char*>(ssid->ucSSID),
+                     ssid->uSSIDLength);
+}
+
+// Returns a map from a network adapter's MAC address to its currently
+// associated WiFi SSID.
+base::small_map<std::map<std::string, std::string>> GetMacSsidMap() {
+  ScopedWlanClientHandle wlan_client_handle;
+  constexpr DWORD kWlanClientVersion = 2;
+  DWORD wlan_current_version = 0;
+
+  auto result =
+      WlanOpenHandle(kWlanClientVersion, nullptr, &wlan_current_version,
+                     &wlan_client_handle.handle);
+  if (result != ERROR_SUCCESS) {
+    LOG(WARNING) << "Failed to open Wlan client handle: " << result;
+    return {};
+  }
+
+  PWLAN_INTERFACE_INFO_LIST wlan_interface_list_raw = nullptr;
+  result = WlanEnumInterfaces(wlan_client_handle.handle, nullptr,
+                              &wlan_interface_list_raw);
+  if (result != ERROR_SUCCESS) {
+    LOG(WARNING) << "Failed to enumerate wireless interfaces: " << result;
+    return {};
+  }
+
+  std::unique_ptr<WLAN_INTERFACE_INFO_LIST, decltype(&WlanApiDeleter)>
+      wlan_interface_list(wlan_interface_list_raw, WlanApiDeleter);
+  auto guid_mac_map = GetInterfaceGuidMacMap();
+  base::small_map<std::map<std::string, std::string>> mac_ssid_map;
+
+  // This loop takes each wireless interface and maps its MAC address to its
+  // associated SSID, if it has one.  Each wireless interface has an interface
+  // GUID which we can use to get its MAC address via |guid_mac_map| and its
+  // associated SSID via WlanQueryInterface.
+  for (DWORD i = 0; i < wlan_interface_list->dwNumberOfItems; ++i) {
+    const auto* interface_info = &wlan_interface_list->InterfaceInfo[i];
+    const auto mac_entry = guid_mac_map.find(interface_info->InterfaceGuid);
+    if (mac_entry == guid_mac_map.end()) {
+      continue;
+    }
+    auto ssid = GetSsidForInterfaceGuid(wlan_client_handle.handle,
+                                        interface_info->InterfaceGuid);
+    if (ssid.empty()) {
+      continue;
+    }
+    mac_ssid_map.insert(std::make_pair(mac_entry->second, std::move(ssid)));
+  }
+  return mac_ssid_map;
+}
+
+}  // namespace
+
 std::vector<DiscoveryNetworkInfo> GetDiscoveryNetworkInfoList() {
-  return std::vector<DiscoveryNetworkInfo>();
+  // Max number of times to retry GetAdaptersAddresses due to
+  // ERROR_BUFFER_OVERFLOW. If GetAdaptersAddresses returns this indefinitely
+  // due to an unforeseen reason, we don't want to be stuck in an endless loop.
+  constexpr int kMaxGetAdaptersAddressTries = 10;
+
+  // Use an initial buffer size of 15KB, as recommended by MSDN. See:
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
+  constexpr int kInitialAddressBufferSize = 15000;
+
+  constexpr ULONG kAddressFlags =
+      GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+      GAA_FLAG_SKIP_DNS_SERVER;
+
+  // Although we need to provide GetAdaptersAddresses with a buffer, there's no
+  // way to know what size to use.  We use a best-guess here but when
+  // GetAdaptersAddresses returns ERROR_BUFFER_OVERFLOW, it means our guess was
+  // too small.  When this happens it will also reset |addresses_buffer_size| to
+  // the required size.  Although it's very unlikely that two successive calls
+  // will both require increasing the buffer size, there's no guarantee that
+  // this won't happen; this is what the maximum retry count guards against.
+  ULONG addresses_buffer_size = kInitialAddressBufferSize;
+  std::unique_ptr<char[]> addresses_buffer;
+  PIP_ADAPTER_ADDRESSES adapter_addresses = nullptr;
+  ULONG result = ERROR_BUFFER_OVERFLOW;
+  for (int i = 0;
+       result == ERROR_BUFFER_OVERFLOW && i < kMaxGetAdaptersAddressTries;
+       ++i) {
+    addresses_buffer.reset(new char[addresses_buffer_size]);
+    adapter_addresses =
+        reinterpret_cast<PIP_ADAPTER_ADDRESSES>(addresses_buffer.get());
+    result = GetAdaptersAddresses(AF_UNSPEC, kAddressFlags, nullptr,
+                                  adapter_addresses, &addresses_buffer_size);
+  }
+
+  if (result != NO_ERROR) {
+    return {};
+  }
+
+  std::vector<DiscoveryNetworkInfo> network_ids;
+  auto mac_ssid_map = GetMacSsidMap();
+  for (const IP_ADAPTER_ADDRESSES* current_adapter = adapter_addresses;
+       current_adapter != nullptr; current_adapter = current_adapter->Next) {
+    // We only want adapters which are up and either Ethernet or wireless, so we
+    // skip everything else here.
+    if (current_adapter->OperStatus != IfOperStatusUp ||
+        (current_adapter->IfType != IF_TYPE_ETHERNET_CSMACD &&
+         current_adapter->IfType != IF_TYPE_IEEE80211)) {
+      continue;
+    }
+
+    // We have to use a slightly roundabout way to get the SSID for each
+    // adapter:
+    // - Enumerate wifi devices to get list of interface GUIDs.
+    // - Enumerate interfaces to get interface GUID -> physical address map.
+    // - Map interface GUIDs to SSID.
+    // - Use GUID -> MAC map to do MAC -> interface GUID  -> SSID.
+    // Although it's theoretically possible to have multiple interfaces per
+    // adapter, most wireless cards don't actually allow multiple
+    // managed-mode interfaces.  However, in the event that there really
+    // are multiple interfaces per adapter (i.e. physical address), we will
+    // simply use the SSID of the first match.  It's unclear how Windows would
+    // handle this case since it's somewhat loose with its use of the words
+    // "adapter" and "interface".
+    std::string name(current_adapter->AdapterName);
+    if (current_adapter->IfType == IF_TYPE_IEEE80211) {
+      std::string adapter_mac(
+          reinterpret_cast<const char*>(current_adapter->PhysicalAddress),
+          current_adapter->PhysicalAddressLength);
+      const auto ssid_entry = mac_ssid_map.find(adapter_mac);
+      if (ssid_entry != mac_ssid_map.end()) {
+        network_ids.emplace_back(name, ssid_entry->second);
+        continue;
+      }
+    }
+    network_ids.emplace_back(
+        name, base::HexEncode(current_adapter->PhysicalAddress,
+                              current_adapter->PhysicalAddressLength));
+  }
+
+  StableSortDiscoveryNetworkInfo(network_ids.begin(), network_ids.end());
+
+  return network_ids;
 }
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index 3c7d8bf..779ee9391 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -222,11 +222,6 @@
   RemoveInvalidRouteControllers(routes);
 }
 
-const std::string& MediaRouterMojoImpl::media_route_provider_extension_id()
-    const {
-  return event_page_request_manager_->media_route_provider_extension_id();
-}
-
 void MediaRouterMojoImpl::RouteResponseReceived(
     const std::string& presentation_id,
     bool is_incognito,
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index 3e9627c..ea5ee20 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -115,9 +115,6 @@
   scoped_refptr<MediaRouteController> GetRouteController(
       const MediaRoute::Id& route_id) override;
 
-  // TODO(crbug.com/597778): Remove this getter.
-  const std::string& media_route_provider_extension_id() const;
-
   void set_instance_id_for_test(const std::string& instance_id) {
     instance_id_ = instance_id;
   }
@@ -218,7 +215,7 @@
 
   // Binds |this| to a Mojo interface request, so that clients can acquire a
   // handle to a MediaRouterMojoImpl instance via the Mojo service connector.
-  // Stores the ID of |extension| in |media_route_provider_extension_id_|.
+  // Passes the extension's ID to the event page request manager.
   void BindToMojoRequest(
       mojo::InterfaceRequest<mojom::MediaRouter> request,
       const extensions::Extension& extension);
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index 1942d62..8827de8 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -70,16 +70,13 @@
 
 }  // namespace
 
-// Used by PresentationServiceDelegateImpl to manage
-// listeners and default presentation info in a render frame.
-// Its lifetime:
-//  * Create an instance with |render_frame_host_id_| if no instance with the
-//    same |render_frame_host_id_| exists in:
-//      PresentationFrameManager::OnPresentationConnection
-//      PresentationFrameManager::OnDefaultPresentationStarted
-//      PresentationFrameManager::SetScreenAvailabilityListener
-//  * Destroy the instance in:
-//      PresentationFrameManager::Reset
+// PresentationFrame interfaces with MediaRouter to maintain the current state
+// of Presentation API within a single render frame, such as the set of
+// PresentationAvailability listeners and PresentationConnections.
+// Instances are lazily created when certain Presentation API is invoked on a
+// frame, and are owned by PresentationServiceDelegateImpl.
+// Instances are destroyed when the corresponding frame navigates, or when it
+// is destroyed.
 class PresentationFrame {
  public:
   PresentationFrame(const RenderFrameHostId& render_frame_host_id,
@@ -94,31 +91,24 @@
       content::PresentationScreenAvailabilityListener* listener);
   bool HasScreenAvailabilityListenerForTest(
       const MediaSource::Id& source_id) const;
-  std::string GetDefaultPresentationId() const;
   void ListenForConnectionStateChange(
       const content::PresentationInfo& connection,
       const content::PresentationConnectionStateChangedCallback&
           state_changed_cb);
 
   void Reset();
-  void RemoveConnection(const std::string& presentation_id,
-                        const MediaRoute::Id& route_id);
 
-  const MediaRoute::Id GetRouteId(const std::string& presentation_id) const;
+  MediaRoute::Id GetRouteId(const std::string& presentation_id) const;
 
-  void OnPresentationConnection(
-      const content::PresentationInfo& presentation_info,
-      const MediaRoute& route);
-  void OnPresentationServiceDelegateDestroyed() const;
-
+  void AddPresentation(const content::PresentationInfo& presentation_info,
+                       const MediaRoute& route);
   void ConnectToPresentation(
       const content::PresentationInfo& presentation_info,
       content::PresentationConnectionPtr controller_connection_ptr,
       content::PresentationConnectionRequest receiver_connection_request);
+  void RemovePresentation(const std::string& presentation_id);
 
  private:
-  MediaSource GetMediaSourceFromListener(
-      content::PresentationScreenAvailabilityListener* listener) const;
   base::small_map<std::map<std::string, MediaRoute>> presentation_id_to_route_;
   base::small_map<
       std::map<std::string, std::unique_ptr<PresentationMediaSinksObserver>>>
@@ -149,17 +139,9 @@
   DCHECK(router_);
 }
 
-PresentationFrame::~PresentationFrame() {
-}
+PresentationFrame::~PresentationFrame() = default;
 
-void PresentationFrame::OnPresentationConnection(
-    const content::PresentationInfo& presentation_info,
-    const MediaRoute& route) {
-  presentation_id_to_route_.insert(
-      std::make_pair(presentation_info.presentation_id, route));
-}
-
-const MediaRoute::Id PresentationFrame::GetRouteId(
+MediaRoute::Id PresentationFrame::GetRouteId(
     const std::string& presentation_id) const {
   auto it = presentation_id_to_route_.find(presentation_id);
   return it != presentation_id_to_route_.end() ? it->second.media_route_id()
@@ -168,7 +150,8 @@
 
 bool PresentationFrame::SetScreenAvailabilityListener(
     content::PresentationScreenAvailabilityListener* listener) {
-  MediaSource source(GetMediaSourceFromListener(listener));
+  MediaSource source =
+      MediaSourceForPresentationUrl(listener->GetAvailabilityUrl());
   if (!IsValidPresentationUrl(source.url())) {
     listener->OnScreenAvailabilityChanged(
         blink::mojom::ScreenAvailability::SOURCE_NOT_SUPPORTED);
@@ -195,7 +178,8 @@
 
 void PresentationFrame::RemoveScreenAvailabilityListener(
     content::PresentationScreenAvailabilityListener* listener) {
-  MediaSource source(GetMediaSourceFromListener(listener));
+  MediaSource source =
+      MediaSourceForPresentationUrl(listener->GetAvailabilityUrl());
   auto sinks_observer_it = url_to_sinks_observer_.find(source.id());
   if (sinks_observer_it != url_to_sinks_observer_.end() &&
       sinks_observer_it->second->listener() == listener) {
@@ -227,47 +211,11 @@
   browser_connection_proxies_.clear();
 }
 
-void PresentationFrame::RemoveConnection(const std::string& presentation_id,
-                                         const MediaRoute::Id& route_id) {
-  // Remove the presentation id mapping so a later call to Reset is a no-op.
-  presentation_id_to_route_.erase(presentation_id);
-
-  browser_connection_proxies_.erase(route_id);
-  // We keep the PresentationConnectionStateChangedCallback registered with MR
-  // so the MRP can tell us when terminate() completed.
-}
-
-void PresentationFrame::ListenForConnectionStateChange(
-    const content::PresentationInfo& connection,
-    const content::PresentationConnectionStateChangedCallback&
-        state_changed_cb) {
-  auto it = presentation_id_to_route_.find(connection.presentation_id);
-  if (it == presentation_id_to_route_.end()) {
-    DLOG(ERROR) << __func__ << "route id not found for presentation: "
-                << connection.presentation_id;
-    return;
-  }
-
-  const MediaRoute::Id& route_id = it->second.media_route_id();
-  if (connection_state_subscriptions_.find(route_id) !=
-      connection_state_subscriptions_.end()) {
-    DLOG(ERROR) << __func__
-                << "Already listening connection state change for route: "
-                << route_id;
-    return;
-  }
-
-  connection_state_subscriptions_.insert(std::make_pair(
-      route_id, router_->AddPresentationConnectionStateChangedCallback(
-                    route_id, state_changed_cb)));
-}
-
-MediaSource PresentationFrame::GetMediaSourceFromListener(
-    content::PresentationScreenAvailabilityListener* listener) const {
-  // If the default presentation URL is empty then fall back to tab mirroring.
-  return listener->GetAvailabilityUrl().is_empty()
-             ? MediaSourceForTab(SessionTabHelper::IdForTab(web_contents_))
-             : MediaSourceForPresentationUrl(listener->GetAvailabilityUrl());
+void PresentationFrame::AddPresentation(
+    const content::PresentationInfo& presentation_info,
+    const MediaRoute& route) {
+  presentation_id_to_route_.insert(
+      std::make_pair(presentation_info.presentation_id, route));
 }
 
 void PresentationFrame::ConnectToPresentation(
@@ -311,296 +259,42 @@
   }
 }
 
-// Used by PresentationServiceDelegateImpl to manage PresentationFrames.
-class PresentationFrameManager {
- public:
-  PresentationFrameManager(content::WebContents* web_contents,
-                           MediaRouter* router);
-  ~PresentationFrameManager();
+void PresentationFrame::RemovePresentation(const std::string& presentation_id) {
+  // Remove the presentation id mapping so a later call to Reset is a no-op.
+  auto it = presentation_id_to_route_.find(presentation_id);
+  if (it == presentation_id_to_route_.end())
+    return;
 
-  // Mirror corresponding APIs in PresentationServiceDelegateImpl.
-  bool SetScreenAvailabilityListener(
-      const RenderFrameHostId& render_frame_host_id,
-      content::PresentationScreenAvailabilityListener* listener);
-  void RemoveScreenAvailabilityListener(
-      const RenderFrameHostId& render_frame_host_id,
-      content::PresentationScreenAvailabilityListener* listener);
-  void ListenForConnectionStateChange(
-      const RenderFrameHostId& render_frame_host_id,
-      const content::PresentationInfo& connection,
-      const content::PresentationConnectionStateChangedCallback&
-          state_changed_cb);
-
-  // Sets or clears the default presentation request and callback for the given
-  // frame. Also sets / clears the default presentation requests for the owning
-  // tab WebContents.
-  void SetDefaultPresentationUrls(
-      const RenderFrameHostId& render_frame_host_id,
-      const std::vector<GURL>& default_presentation_urls,
-      content::DefaultPresentationConnectionCallback callback);
-  void AddDelegateObserver(const RenderFrameHostId& render_frame_host_id,
-                           DelegateObserver* observer);
-  void RemoveDelegateObserver(const RenderFrameHostId& render_frame_host_id);
-  void AddDefaultPresentationRequestObserver(
-      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
-          observer);
-  void RemoveDefaultPresentationRequestObserver(
-      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
-          observer);
-  void Reset(const RenderFrameHostId& render_frame_host_id);
-  void RemoveConnection(const RenderFrameHostId& render_frame_host_id,
-                        const MediaRoute::Id& route_id,
-                        const std::string& presentation_id);
-  bool HasScreenAvailabilityListenerForTest(
-      const RenderFrameHostId& render_frame_host_id,
-      const MediaSource::Id& source_id) const;
-  void SetMediaRouterForTest(MediaRouter* router);
-
-  void OnPresentationConnection(
-      const RenderFrameHostId& render_frame_host_id,
-      const content::PresentationInfo& presentation_info,
-      const MediaRoute& route);
-  void OnDefaultPresentationStarted(
-      const PresentationRequest& request,
-      const content::PresentationInfo& presentation_info,
-      const MediaRoute& route);
-
-  void ConnectToPresentation(
-      const RenderFrameHostId& render_frame_host_id,
-      const content::PresentationInfo& presentation_info,
-      content::PresentationConnectionPtr controller_connection_ptr,
-      content::PresentationConnectionRequest receiver_connection_request);
-
-  const MediaRoute::Id GetRouteId(const RenderFrameHostId& render_frame_host_id,
-                                  const std::string& presentation_id) const;
-
-  const PresentationRequest* default_presentation_request() const {
-    return default_presentation_request_.get();
-  }
-
- private:
-  PresentationFrame* GetOrAddPresentationFrame(
-      const RenderFrameHostId& render_frame_host_id);
-
-  // Sets the default presentation request for the owning WebContents and
-  // notifies observers of changes.
-  void SetDefaultPresentationRequest(
-      const PresentationRequest& default_presentation_request);
-
-  // Clears the default presentation request for the owning WebContents and
-  // notifies observers of changes. Also resets
-  // |default_presentation_started_callback_|.
-  void ClearDefaultPresentationRequest();
-
-  bool IsMainFrame(const RenderFrameHostId& render_frame_host_id) const;
-
-  // Maps a frame identifier to a PresentationFrame object for frames
-  // that are using presentation API.
-  std::unordered_map<RenderFrameHostId, std::unique_ptr<PresentationFrame>,
-                     RenderFrameHostIdHasher>
-      presentation_frames_;
-
-  // Default presentation request for the owning tab WebContents.
-  std::unique_ptr<PresentationRequest> default_presentation_request_;
-
-  // Callback to invoke when default presentation has started.
-  content::DefaultPresentationConnectionCallback
-      default_presentation_started_callback_;
-
-  // References to the observers listening for changes to this tab WebContent's
-  // default presentation.
-  base::ObserverList<
-      PresentationServiceDelegateImpl::DefaultPresentationRequestObserver>
-      default_presentation_request_observers_;
-
-  // References to the owning WebContents, and the corresponding MediaRouter.
-  MediaRouter* router_;
-  content::WebContents* web_contents_;
-};
-
-PresentationFrameManager::PresentationFrameManager(
-    content::WebContents* web_contents,
-    MediaRouter* router)
-    : router_(router), web_contents_(web_contents) {
-  DCHECK(web_contents_);
-  DCHECK(router_);
+  auto route_id = it->second.media_route_id();
+  presentation_id_to_route_.erase(presentation_id);
+  browser_connection_proxies_.erase(route_id);
+  // We keep the PresentationConnectionStateChangedCallback registered with MR
+  // so the MRP can tell us when terminate() completed.
 }
 
-PresentationFrameManager::~PresentationFrameManager() {}
-
-void PresentationFrameManager::OnPresentationConnection(
-    const RenderFrameHostId& render_frame_host_id,
-    const content::PresentationInfo& presentation_info,
-    const MediaRoute& route) {
-  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
-  presentation_frame->OnPresentationConnection(presentation_info, route);
-}
-
-void PresentationFrameManager::OnDefaultPresentationStarted(
-    const PresentationRequest& request,
-    const content::PresentationInfo& presentation_info,
-    const MediaRoute& route) {
-  OnPresentationConnection(request.render_frame_host_id(), presentation_info,
-                           route);
-
-  if (default_presentation_request_ &&
-      default_presentation_request_->Equals(request)) {
-    default_presentation_started_callback_.Run(presentation_info);
-  }
-}
-
-void PresentationFrameManager::ConnectToPresentation(
-    const RenderFrameHostId& render_frame_host_id,
-    const content::PresentationInfo& presentation_info,
-    content::PresentationConnectionPtr controller_connection_ptr,
-    content::PresentationConnectionRequest receiver_connection_request) {
-  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
-  presentation_frame->ConnectToPresentation(
-      presentation_info, std::move(controller_connection_ptr),
-      std::move(receiver_connection_request));
-}
-
-const MediaRoute::Id PresentationFrameManager::GetRouteId(
-    const RenderFrameHostId& render_frame_host_id,
-    const std::string& presentation_id) const {
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  return it != presentation_frames_.end()
-             ? it->second->GetRouteId(presentation_id)
-             : MediaRoute::Id();
-}
-
-bool PresentationFrameManager::SetScreenAvailabilityListener(
-    const RenderFrameHostId& render_frame_host_id,
-    content::PresentationScreenAvailabilityListener* listener) {
-  DCHECK(listener);
-  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
-  return presentation_frame->SetScreenAvailabilityListener(listener);
-}
-
-void PresentationFrameManager::RemoveScreenAvailabilityListener(
-    const RenderFrameHostId& render_frame_host_id,
-    content::PresentationScreenAvailabilityListener* listener) {
-  DCHECK(listener);
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  if (it != presentation_frames_.end())
-    it->second->RemoveScreenAvailabilityListener(listener);
-}
-
-bool PresentationFrameManager::HasScreenAvailabilityListenerForTest(
-    const RenderFrameHostId& render_frame_host_id,
-    const MediaSource::Id& source_id) const {
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  return it != presentation_frames_.end() &&
-         it->second->HasScreenAvailabilityListenerForTest(source_id);
-}
-
-void PresentationFrameManager::ListenForConnectionStateChange(
-    const RenderFrameHostId& render_frame_host_id,
+void PresentationFrame::ListenForConnectionStateChange(
     const content::PresentationInfo& connection,
     const content::PresentationConnectionStateChangedCallback&
         state_changed_cb) {
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  if (it != presentation_frames_.end())
-    it->second->ListenForConnectionStateChange(connection, state_changed_cb);
-}
-
-void PresentationFrameManager::SetDefaultPresentationUrls(
-    const RenderFrameHostId& render_frame_host_id,
-    const std::vector<GURL>& default_presentation_urls,
-    content::DefaultPresentationConnectionCallback callback) {
-  if (!IsMainFrame(render_frame_host_id))
+  auto it = presentation_id_to_route_.find(connection.presentation_id);
+  if (it == presentation_id_to_route_.end()) {
+    DLOG(ERROR) << __func__ << "route id not found for presentation: "
+                << connection.presentation_id;
     return;
-
-  if (default_presentation_urls.empty()) {
-    ClearDefaultPresentationRequest();
-  } else {
-    DCHECK(!callback.is_null());
-    const auto& frame_origin =
-        GetLastCommittedURLForFrame(render_frame_host_id);
-    PresentationRequest request(render_frame_host_id, default_presentation_urls,
-                                frame_origin);
-    default_presentation_started_callback_ = callback;
-    SetDefaultPresentationRequest(request);
-  }
-}
-
-void PresentationFrameManager::AddDefaultPresentationRequestObserver(
-    PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
-        observer) {
-  default_presentation_request_observers_.AddObserver(observer);
-}
-
-void PresentationFrameManager::RemoveDefaultPresentationRequestObserver(
-    PresentationServiceDelegateImpl::DefaultPresentationRequestObserver*
-        observer) {
-  default_presentation_request_observers_.RemoveObserver(observer);
-}
-
-void PresentationFrameManager::Reset(
-    const RenderFrameHostId& render_frame_host_id) {
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  if (it != presentation_frames_.end()) {
-    it->second->Reset();
-    presentation_frames_.erase(it);
   }
 
-  if (default_presentation_request_ &&
-      render_frame_host_id ==
-          default_presentation_request_->render_frame_host_id()) {
-    ClearDefaultPresentationRequest();
-  }
-}
-
-void PresentationFrameManager::RemoveConnection(
-    const RenderFrameHostId& render_frame_host_id,
-    const MediaRoute::Id& route_id,
-    const std::string& presentation_id) {
-  const auto it = presentation_frames_.find(render_frame_host_id);
-  if (it != presentation_frames_.end())
-    it->second->RemoveConnection(route_id, presentation_id);
-}
-
-PresentationFrame* PresentationFrameManager::GetOrAddPresentationFrame(
-    const RenderFrameHostId& render_frame_host_id) {
-  std::unique_ptr<PresentationFrame>& presentation_frame =
-      presentation_frames_[render_frame_host_id];
-  if (!presentation_frame) {
-    presentation_frame.reset(new PresentationFrame(
-        render_frame_host_id, web_contents_, router_));
-  }
-  return presentation_frame.get();
-}
-
-void PresentationFrameManager::ClearDefaultPresentationRequest() {
-  default_presentation_started_callback_.Reset();
-  if (!default_presentation_request_)
+  const MediaRoute::Id& route_id = it->second.media_route_id();
+  if (connection_state_subscriptions_.find(route_id) !=
+      connection_state_subscriptions_.end()) {
+    DLOG(ERROR) << __func__
+                << "Already listening connection state change for route: "
+                << route_id;
     return;
+  }
 
-  default_presentation_request_.reset();
-  for (auto& observer : default_presentation_request_observers_)
-    observer.OnDefaultPresentationRemoved();
-}
-
-bool PresentationFrameManager::IsMainFrame(
-    const RenderFrameHostId& render_frame_host_id) const {
-  RenderFrameHost* main_frame = web_contents_->GetMainFrame();
-  return main_frame && GetRenderFrameHostId(main_frame) == render_frame_host_id;
-}
-
-void PresentationFrameManager::SetDefaultPresentationRequest(
-    const PresentationRequest& default_presentation_request) {
-  if (default_presentation_request_ &&
-      default_presentation_request_->Equals(default_presentation_request))
-    return;
-
-  default_presentation_request_.reset(
-      new PresentationRequest(default_presentation_request));
-  for (auto& observer : default_presentation_request_observers_)
-    observer.OnDefaultPresentationChanged(*default_presentation_request_);
-}
-
-void PresentationFrameManager::SetMediaRouterForTest(MediaRouter* router) {
-  router_ = router;
+  connection_state_subscriptions_.insert(std::make_pair(
+      route_id, router_->AddPresentationConnectionStateChangedCallback(
+                    route_id, state_changed_cb)));
 }
 
 PresentationServiceDelegateImpl*
@@ -617,14 +311,12 @@
     : web_contents_(web_contents),
       router_(MediaRouterFactory::GetApiForBrowserContext(
           web_contents_->GetBrowserContext())),
-      frame_manager_(new PresentationFrameManager(web_contents, router_)),
       weak_factory_(this) {
   DCHECK(web_contents_);
   DCHECK(router_);
 }
 
-PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() {
-}
+PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() = default;
 
 void PresentationServiceDelegateImpl::AddObserver(int render_process_id,
                                                   int render_frame_id,
@@ -643,8 +335,9 @@
     int render_frame_id,
     content::PresentationScreenAvailabilityListener* listener) {
   DCHECK(listener);
-  return frame_manager_->SetScreenAvailabilityListener(
-      RenderFrameHostId(render_process_id, render_frame_id), listener);
+  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
+  return presentation_frame->SetScreenAvailabilityListener(listener);
 }
 
 void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener(
@@ -652,14 +345,36 @@
     int render_frame_id,
     content::PresentationScreenAvailabilityListener* listener) {
   DCHECK(listener);
-  frame_manager_->RemoveScreenAvailabilityListener(
-      RenderFrameHostId(render_process_id, render_frame_id), listener);
+  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  if (it != presentation_frames_.end())
+    it->second->RemoveScreenAvailabilityListener(listener);
 }
 
 void PresentationServiceDelegateImpl::Reset(int render_process_id,
                                             int render_frame_id) {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
-  frame_manager_->Reset(render_frame_host_id);
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  if (it != presentation_frames_.end()) {
+    it->second->Reset();
+    presentation_frames_.erase(it);
+  }
+
+  if (default_presentation_request_ &&
+      render_frame_host_id ==
+          default_presentation_request_->render_frame_host_id()) {
+    ClearDefaultPresentationRequest();
+  }
+}
+
+PresentationFrame* PresentationServiceDelegateImpl::GetOrAddPresentationFrame(
+    const RenderFrameHostId& render_frame_host_id) {
+  auto& presentation_frame = presentation_frames_[render_frame_host_id];
+  if (!presentation_frame) {
+    presentation_frame.reset(
+        new PresentationFrame(render_frame_host_id, web_contents_, router_));
+  }
+  return presentation_frame.get();
 }
 
 void PresentationServiceDelegateImpl::SetDefaultPresentationUrls(
@@ -668,8 +383,20 @@
     const std::vector<GURL>& default_presentation_urls,
     content::DefaultPresentationConnectionCallback callback) {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
-  frame_manager_->SetDefaultPresentationUrls(
-      render_frame_host_id, default_presentation_urls, std::move(callback));
+  if (!IsMainFrame(render_frame_host_id))
+    return;
+
+  if (default_presentation_urls.empty()) {
+    ClearDefaultPresentationRequest();
+    return;
+  }
+
+  DCHECK(!callback.is_null());
+  auto frame_origin = GetLastCommittedURLForFrame(render_frame_host_id);
+  PresentationRequest request(render_frame_host_id, default_presentation_urls,
+                              frame_origin);
+  default_presentation_started_callback_ = std::move(callback);
+  SetDefaultPresentationRequest(request);
 }
 
 void PresentationServiceDelegateImpl::OnJoinRouteResponse(
@@ -691,9 +418,8 @@
     DCHECK_EQ(presentation_id, result.presentation_id());
     content::PresentationInfo presentation_info(presentation_url,
                                                 result.presentation_id());
-    frame_manager_->OnPresentationConnection(
-        RenderFrameHostId(render_process_id, render_frame_id),
-        presentation_info, *result.route());
+    AddPresentation(RenderFrameHostId(render_process_id, render_frame_id),
+                    presentation_info, *result.route());
     std::move(success_cb).Run(presentation_info);
   }
 }
@@ -708,12 +434,27 @@
            << "route_id: " << route.media_route_id()
            << ", presentation URL: " << new_presentation_info.presentation_url
            << ", presentation ID: " << new_presentation_info.presentation_id;
-  frame_manager_->OnPresentationConnection(
-      RenderFrameHostId(render_process_id, render_frame_id),
-      new_presentation_info, route);
+  AddPresentation(RenderFrameHostId(render_process_id, render_frame_id),
+                  new_presentation_info, route);
   std::move(success_cb).Run(new_presentation_info);
 }
 
+void PresentationServiceDelegateImpl::AddPresentation(
+    const RenderFrameHostId& render_frame_host_id,
+    const content::PresentationInfo& presentation_info,
+    const MediaRoute& route) {
+  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
+  presentation_frame->AddPresentation(presentation_info, route);
+}
+
+void PresentationServiceDelegateImpl::RemovePresentation(
+    const RenderFrameHostId& render_frame_host_id,
+    const std::string& presentation_id) {
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  if (it != presentation_frames_.end())
+    it->second->RemovePresentation(presentation_id);
+}
+
 void PresentationServiceDelegateImpl::StartPresentation(
     int render_process_id,
     int render_frame_id,
@@ -745,7 +486,7 @@
           GetLastCommittedURLForFrame(render_frame_host_id),
           base::BindOnce(
               &PresentationServiceDelegateImpl::OnStartPresentationSucceeded,
-              weak_factory_.GetWeakPtr(), render_process_id, render_frame_id,
+              GetWeakPtr(), render_process_id, render_frame_id,
               std::move(success_cb)),
           std::move(error_cb)));
   MediaRouterDialogController* controller =
@@ -774,7 +515,7 @@
     return;
   }
 
-  const url::Origin& origin = GetLastCommittedURLForFrame(
+  auto origin = GetLastCommittedURLForFrame(
       RenderFrameHostId(render_process_id, render_frame_id));
 
 #if !defined(OS_ANDROID)
@@ -816,11 +557,10 @@
     const GURL& presentation_url = presentation_urls[0];
     bool incognito = web_contents_->GetBrowserContext()->IsOffTheRecord();
     std::vector<MediaRouteResponseCallback> route_response_callbacks;
-    route_response_callbacks.push_back(
-        base::BindOnce(&PresentationServiceDelegateImpl::OnJoinRouteResponse,
-                       weak_factory_.GetWeakPtr(), render_process_id,
-                       render_frame_id, presentation_url, presentation_id,
-                       std::move(success_cb), std::move(error_cb)));
+    route_response_callbacks.push_back(base::BindOnce(
+        &PresentationServiceDelegateImpl::OnJoinRouteResponse, GetWeakPtr(),
+        render_process_id, render_frame_id, presentation_url, presentation_id,
+        std::move(success_cb), std::move(error_cb)));
     router_->JoinRoute(MediaSourceForPresentationUrl(presentation_url).id(),
                        presentation_id, origin, web_contents_,
                        std::move(route_response_callbacks), base::TimeDelta(),
@@ -833,8 +573,7 @@
     int render_frame_id,
     const std::string& presentation_id) {
   const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
-  const MediaRoute::Id& route_id =
-      frame_manager_->GetRouteId(rfh_id, presentation_id);
+  auto route_id = GetRouteId(rfh_id, presentation_id);
   if (route_id.empty()) {
     DVLOG(1) << "No active route for: " << presentation_id;
     return;
@@ -851,7 +590,7 @@
   } else {
     router_->DetachRoute(route_id);
   }
-  frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id);
+  RemovePresentation(rfh_id, presentation_id);
   // TODO(mfoltz): close() should always succeed so there is no need to keep the
   // state_changed_cb around - remove it and fire the ChangeEvent on the
   // PresentationConnection in Blink.
@@ -862,14 +601,13 @@
     int render_frame_id,
     const std::string& presentation_id) {
   const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
-  const MediaRoute::Id& route_id =
-      frame_manager_->GetRouteId(rfh_id, presentation_id);
+  auto route_id = GetRouteId(rfh_id, presentation_id);
   if (route_id.empty()) {
     DVLOG(1) << "No active route for: " << presentation_id;
     return;
   }
   router_->TerminateRoute(route_id);
-  frame_manager_->RemoveConnection(rfh_id, presentation_id, route_id);
+  RemovePresentation(rfh_id, presentation_id);
 }
 
 void PresentationServiceDelegateImpl::SendMessage(
@@ -878,9 +616,9 @@
     const content::PresentationInfo& presentation_info,
     content::PresentationConnectionMessage message,
     SendMessageCallback send_message_cb) {
-  const MediaRoute::Id& route_id = frame_manager_->GetRouteId(
-      RenderFrameHostId(render_process_id, render_frame_id),
-      presentation_info.presentation_id);
+  auto route_id =
+      GetRouteId(RenderFrameHostId(render_process_id, render_frame_id),
+                 presentation_info.presentation_id);
   if (route_id.empty()) {
     DVLOG(1) << "No active route for  " << presentation_info.presentation_id;
     std::move(send_message_cb).Run(false);
@@ -904,9 +642,10 @@
     const content::PresentationInfo& connection,
     const content::PresentationConnectionStateChangedCallback&
         state_changed_cb) {
-  frame_manager_->ListenForConnectionStateChange(
-      RenderFrameHostId(render_process_id, render_frame_id), connection,
-      state_changed_cb);
+  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  if (it != presentation_frames_.end())
+    it->second->ListenForConnectionStateChange(connection, state_changed_cb);
 }
 
 void PresentationServiceDelegateImpl::ConnectToPresentation(
@@ -916,9 +655,10 @@
     content::PresentationConnectionPtr controller_connection_ptr,
     content::PresentationConnectionRequest receiver_connection_request) {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
-  frame_manager_->ConnectToPresentation(render_frame_host_id, presentation_info,
-                                        std::move(controller_connection_ptr),
-                                        std::move(receiver_connection_request));
+  auto* presentation_frame = GetOrAddPresentationFrame(render_frame_host_id);
+  presentation_frame->ConnectToPresentation(
+      presentation_info, std::move(controller_connection_ptr),
+      std::move(receiver_connection_request));
 }
 
 void PresentationServiceDelegateImpl::OnRouteResponse(
@@ -932,28 +672,32 @@
 
   content::PresentationInfo presentation_info(result.presentation_url(),
                                               result.presentation_id());
-  frame_manager_->OnDefaultPresentationStarted(
-      presentation_request, presentation_info, *result.route());
+  AddPresentation(presentation_request.render_frame_host_id(),
+                  presentation_info, *result.route());
+  if (default_presentation_request_ &&
+      default_presentation_request_->Equals(presentation_request)) {
+    default_presentation_started_callback_.Run(presentation_info);
+  }
 }
 
 void PresentationServiceDelegateImpl::AddDefaultPresentationRequestObserver(
     DefaultPresentationRequestObserver* observer) {
-  frame_manager_->AddDefaultPresentationRequestObserver(observer);
+  default_presentation_request_observers_.AddObserver(observer);
 }
 
 void PresentationServiceDelegateImpl::RemoveDefaultPresentationRequestObserver(
     DefaultPresentationRequestObserver* observer) {
-  frame_manager_->RemoveDefaultPresentationRequestObserver(observer);
+  default_presentation_request_observers_.RemoveObserver(observer);
 }
 
 PresentationRequest
 PresentationServiceDelegateImpl::GetDefaultPresentationRequest() const {
   DCHECK(HasDefaultPresentationRequest());
-  return *frame_manager_->default_presentation_request();
+  return *default_presentation_request_;
 }
 
 bool PresentationServiceDelegateImpl::HasDefaultPresentationRequest() const {
-  return frame_manager_->default_presentation_request() != nullptr;
+  return default_presentation_request_ != nullptr;
 }
 
 base::WeakPtr<PresentationServiceDelegateImpl>
@@ -964,7 +708,6 @@
 void PresentationServiceDelegateImpl::SetMediaRouterForTest(
     MediaRouter* router) {
   router_ = router;
-  frame_manager_->SetMediaRouterForTest(router);
 }
 
 bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerForTest(
@@ -972,8 +715,47 @@
     int render_frame_id,
     const MediaSource::Id& source_id) const {
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
-  return frame_manager_->HasScreenAvailabilityListenerForTest(
-      render_frame_host_id, source_id);
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  return it != presentation_frames_.end() &&
+         it->second->HasScreenAvailabilityListenerForTest(source_id);
+}
+
+void PresentationServiceDelegateImpl::SetDefaultPresentationRequest(
+    const PresentationRequest& default_presentation_request) {
+  if (default_presentation_request_ &&
+      default_presentation_request_->Equals(default_presentation_request))
+    return;
+
+  default_presentation_request_.reset(
+      new PresentationRequest(default_presentation_request));
+  for (auto& observer : default_presentation_request_observers_)
+    observer.OnDefaultPresentationChanged(*default_presentation_request_);
+}
+
+void PresentationServiceDelegateImpl::ClearDefaultPresentationRequest() {
+  default_presentation_started_callback_.Reset();
+  if (!default_presentation_request_)
+    return;
+
+  default_presentation_request_.reset();
+  for (auto& observer : default_presentation_request_observers_)
+    observer.OnDefaultPresentationRemoved();
+}
+
+// TODO(imcheng): Move this check to PresentationServiceImpl.
+bool PresentationServiceDelegateImpl::IsMainFrame(
+    const RenderFrameHostId& render_frame_host_id) const {
+  RenderFrameHost* main_frame = web_contents_->GetMainFrame();
+  return main_frame && GetRenderFrameHostId(main_frame) == render_frame_host_id;
+}
+
+MediaRoute::Id PresentationServiceDelegateImpl::GetRouteId(
+    const RenderFrameHostId& render_frame_host_id,
+    const std::string& presentation_id) const {
+  const auto it = presentation_frames_.find(render_frame_host_id);
+  return it != presentation_frames_.end()
+             ? it->second->GetRouteId(presentation_id)
+             : MediaRoute::Id();
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation_service_delegate_impl.h
index 0e368db7..f98a8eb 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.h
@@ -38,7 +38,7 @@
 namespace media_router {
 
 class MediaRoute;
-class PresentationFrameManager;
+class PresentationFrame;
 class RouteRequestResult;
 
 // Implementation of PresentationServiceDelegate that interfaces an instance of
@@ -147,7 +147,7 @@
   void RemoveDefaultPresentationRequestObserver(
       DefaultPresentationRequestObserver* observer);
 
-  // Gets the default presentation request for the owning tab WebContents. It
+  // Gets the default presentation request for the owning WebContents. It
   // is an error to call this method if the default presentation request does
   // not exist.
   PresentationRequest GetDefaultPresentationRequest() const;
@@ -186,10 +186,8 @@
 
   explicit PresentationServiceDelegateImpl(content::WebContents* web_contents);
 
-  // Returns |listener|'s presentation URL as a MediaSource. If |listener| does
-  // not have a persentation URL, returns the tab mirroring MediaSource.
-  MediaSource GetMediaSourceFromListener(
-      content::PresentationScreenAvailabilityListener* listener);
+  PresentationFrame* GetOrAddPresentationFrame(
+      const RenderFrameHostId& render_frame_host_id);
 
   void OnJoinRouteResponse(
       int render_process_id,
@@ -207,6 +205,39 @@
       const content::PresentationInfo& new_presentation_info,
       const MediaRoute& route);
 
+  // Notifies the PresentationFrame of |render_frame_host_id| that a
+  // presentation and its corresponding MediaRoute has been created.
+  // The PresentationFrame will be created if it does not already exist.
+  // This must be called before |ConnectToPresentation()|.
+  void AddPresentation(const RenderFrameHostId& render_frame_host_id,
+                       const content::PresentationInfo& presentation_info,
+                       const MediaRoute& route);
+
+  // Notifies the PresentationFrame of |render_frame_host_id| that a
+  // presentation and its corresponding MediaRoute has been removed.
+  void RemovePresentation(const RenderFrameHostId& render_frame_host_id,
+                          const std::string& presentation_id);
+
+  // Sets the default presentation request for the owning WebContents and
+  // notifies observers of changes.
+  void SetDefaultPresentationRequest(
+      const PresentationRequest& default_presentation_request);
+
+  // Clears the default presentation request for the owning WebContents and
+  // notifies observers of changes. Also resets
+  // |default_presentation_started_callback_|.
+  void ClearDefaultPresentationRequest();
+
+  // Returns |true| if the given frame is the main frame of the associated
+  // WebContents.
+  // NOTE: This method will be removed in an upcoming patch.
+  bool IsMainFrame(const RenderFrameHostId& render_frame_host_id) const;
+
+  // Returns the ID of the route corresponding to |presentation_id| in the given
+  // frame, or empty if no such route exist.
+  MediaRoute::Id GetRouteId(const RenderFrameHostId& render_frame_host_id,
+                            const std::string& presentation_id) const;
+
 #if !defined(OS_ANDROID)
   // Returns true if auto-join requests should be cancelled for |origin|.
   bool ShouldCancelAutoJoinForOrigin(const url::Origin& origin) const;
@@ -217,7 +248,25 @@
   content::WebContents* const web_contents_;
   MediaRouter* router_;
 
-  std::unique_ptr<PresentationFrameManager> frame_manager_;
+  // References to the observers listening for changes to the default
+  // presentation of the associated WebContents.
+  base::ObserverList<DefaultPresentationRequestObserver>
+      default_presentation_request_observers_;
+
+  // Default presentation request for the owning WebContents.
+  std::unique_ptr<PresentationRequest> default_presentation_request_;
+
+  // Callback to invoke when the default presentation has started.
+  content::DefaultPresentationConnectionCallback
+      default_presentation_started_callback_;
+
+  // Maps a frame identifier to a PresentationFrame object for frames
+  // that are using Presentation API.
+  std::unordered_map<RenderFrameHostId,
+                     std::unique_ptr<PresentationFrame>,
+                     RenderFrameHostIdHasher>
+      presentation_frames_;
+
   PresentationServiceDelegateObservers observers_;
 
   base::WeakPtrFactory<PresentationServiceDelegateImpl> weak_factory_;
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
index f935850..be0061f 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
@@ -143,7 +143,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
-                       AddAndRemoveTracksWithSharedStream) {
+                       DISABLED_AddAndRemoveTracksWithSharedStream) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
diff --git a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
index d5fc4c0..c9b31ff7 100644
--- a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/notifications/notification_channels_provider_android.h"
 
+#include <map>
+#include <vector>
+
 #include "base/memory/ptr_util.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/values.h"
@@ -20,52 +23,100 @@
 #include "url/gurl.h"
 
 using ::testing::_;
-using ::testing::InSequence;
-using ::testing::MockFunction;
-using ::testing::Return;
 
 namespace {
 const char kTestOrigin[] = "https://example.com";
 }  // namespace
 
-class MockNotificationChannelsBridge
+class FakeNotificationChannelsBridge
     : public NotificationChannelsProviderAndroid::NotificationChannelsBridge {
  public:
-  ~MockNotificationChannelsBridge() = default;
-  MOCK_METHOD0(ShouldUseChannelSettings, bool());
-  MOCK_METHOD2(CreateChannel, void(const std::string&, bool));
-  MOCK_METHOD1(GetChannelStatus, NotificationChannelStatus(const std::string&));
-  MOCK_METHOD1(DeleteChannel, void(const std::string&));
-  MOCK_METHOD0(GetChannels, std::vector<NotificationChannel>());
+  explicit FakeNotificationChannelsBridge(bool should_use_channels) {
+    should_use_channels_ = should_use_channels;
+  }
+
+  ~FakeNotificationChannelsBridge() override = default;
+
+  void SetChannelStatus(const std::string& origin,
+                        NotificationChannelStatus status) {
+    switch (status) {
+      case NotificationChannelStatus::UNAVAILABLE:
+        channels_.erase(origin);
+        return;
+      case NotificationChannelStatus::ENABLED:
+      case NotificationChannelStatus::BLOCKED:
+        auto entry = channels_.find(origin);
+        if (entry != channels_.end())
+          entry->second.status = status;
+        else
+          channels_.emplace(origin, NotificationChannel(origin, status));
+        return;
+    }
+  }
+
+  // NotificationChannelsBridge methods.
+
+  bool ShouldUseChannelSettings() override { return should_use_channels_; }
+
+  void CreateChannel(const std::string& origin, bool enabled) override {
+    // Note if a channel for the given origin was already created, this is a
+    // no-op. This is intentional, to match the Android Channels API.
+    channels_.emplace(
+        origin, NotificationChannel(
+                    origin, enabled ? NotificationChannelStatus::ENABLED
+                                    : NotificationChannelStatus::BLOCKED));
+  }
+
+  NotificationChannelStatus GetChannelStatus(
+      const std::string& origin) override {
+    auto entry = channels_.find(origin);
+    if (entry != channels_.end())
+      return entry->second.status;
+    return NotificationChannelStatus::UNAVAILABLE;
+  }
+
+  void DeleteChannel(const std::string& origin) override {
+    channels_.erase(origin);
+  }
+
+  std::vector<NotificationChannel> GetChannels() override {
+    std::vector<NotificationChannel> channels;
+    for (auto it = channels_.begin(); it != channels_.end(); it++)
+      channels.push_back(it->second);
+    return channels;
+  }
+
+ private:
+  bool should_use_channels_;
+  std::map<std::string, NotificationChannel> channels_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeNotificationChannelsBridge);
 };
 
 class NotificationChannelsProviderAndroidTest : public testing::Test {
  public:
-  NotificationChannelsProviderAndroidTest()
-      : mock_bridge_(new MockNotificationChannelsBridge()) {}
+  NotificationChannelsProviderAndroidTest() = default;
+
   ~NotificationChannelsProviderAndroidTest() override {
     channels_provider_->ShutdownOnUIThread();
   }
 
  protected:
   void InitChannelsProvider(bool should_use_channels) {
-    EXPECT_CALL(*mock_bridge_, ShouldUseChannelSettings())
-        .WillOnce(Return(should_use_channels));
-    ON_CALL(*mock_bridge_, GetChannelStatus(_))
-        .WillByDefault(Return(NotificationChannelStatus::UNAVAILABLE));
+    fake_bridge_ = new FakeNotificationChannelsBridge(should_use_channels);
 
     // Can't use base::MakeUnique because the provider's constructor is private.
     channels_provider_ =
         base::WrapUnique(new NotificationChannelsProviderAndroid(
-            base::WrapUnique(mock_bridge_)));
+            base::WrapUnique(fake_bridge_)));
   }
 
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
-  // No leak because ownership is passed to channels_provider_ in constructor.
-  MockNotificationChannelsBridge* mock_bridge_;
-
   std::unique_ptr<NotificationChannelsProviderAndroid> channels_provider_;
+
+  // No leak because ownership is passed to channels_provider_ in constructor.
+  FakeNotificationChannelsBridge* fake_bridge_;
 };
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -82,9 +133,6 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingAllowedWhenChannelUnavailable_CreatesEnabledChannel) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::UNAVAILABLE));
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, true /* enabled */));
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -92,14 +140,15 @@
       new base::Value(CONTENT_SETTING_ALLOW));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::ENABLED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingBlockedWhenChannelUnavailable_CreatesDisabledChannel) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::UNAVAILABLE));
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, false /* enabled */));
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -107,13 +156,16 @@
       new base::Value(CONTENT_SETTING_BLOCK));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::BLOCKED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingAllowedWhenChannelAllowed_NoopAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::ENABLED));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -121,13 +173,16 @@
       new base::Value(CONTENT_SETTING_ALLOW));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::ENABLED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingBlockedWhenChannelBlocked_NoopAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannelStatus(kTestOrigin))
-      .WillOnce(Return(NotificationChannelStatus::BLOCKED));
+  fake_bridge_->CreateChannel(kTestOrigin, false);
 
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
@@ -135,17 +190,22 @@
       new base::Value(CONTENT_SETTING_BLOCK));
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(1u, fake_bridge_->GetChannels().size());
+  EXPECT_EQ(
+      NotificationChannel(kTestOrigin, NotificationChannelStatus::BLOCKED),
+      fake_bridge_->GetChannels()[0]);
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        SetWebsiteSettingDefault_DeletesChannelAndReturnsTrue) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(kTestOrigin));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
   bool result = channels_provider_->SetWebsiteSetting(
       ContentSettingsPattern::FromString(kTestOrigin), ContentSettingsPattern(),
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(), nullptr);
 
   EXPECT_TRUE(result);
+  EXPECT_EQ(0u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -166,7 +226,6 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenNoChannelsExist) {
   InitChannelsProvider(true /* should_use_channels */);
-  EXPECT_CALL(*mock_bridge_, GetChannels());
   EXPECT_FALSE(channels_provider_->GetRuleIterator(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
       false /* incognito */));
@@ -175,9 +234,8 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenOneBlockedChannelExists) {
   InitChannelsProvider(true /* should_use_channels */);
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back(kTestOrigin, NotificationChannelStatus::BLOCKED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel(kTestOrigin, false);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -193,9 +251,8 @@
 TEST_F(NotificationChannelsProviderAndroidTest,
        GetRuleIteratorWhenOneAllowedChannelExists) {
   InitChannelsProvider(true /* should_use_channels */);
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back(kTestOrigin, NotificationChannelStatus::ENABLED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel(kTestOrigin, true);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -212,9 +269,9 @@
        GetRuleIteratorWhenMultipleChannelsExist) {
   InitChannelsProvider(true /* should_use_channels */);
   std::vector<NotificationChannel> channels;
-  channels.emplace_back("https://abc.com", NotificationChannelStatus::ENABLED);
-  channels.emplace_back("https://xyz.com", NotificationChannelStatus::BLOCKED);
-  EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  fake_bridge_->CreateChannel("https://abc.com", true);
+  fake_bridge_->CreateChannel("https://xyz.com", false);
+
   std::unique_ptr<content_settings::RuleIterator> result =
       channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                           std::string(), false /* incognito */);
@@ -239,56 +296,32 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  // Set up sequenced expectations. The observer should be notified on the first
-  // GetRuleIterator, and then only if channel status has changed to blocked.
-  // See "Using Check Points" section of the GTest Cookbook:
-  // https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#using-check-points
-  MockFunction<void(std::string check_point_name)> check;
-  {
-    InSequence s;
-    EXPECT_CALL(check, Call("0: GetRuleIterator never called"));
-    // Report channel as enabled initially.
-    std::vector<NotificationChannel> channels;
-    channels.emplace_back("https://example.com",
-                          NotificationChannelStatus::ENABLED);
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
+  // Create channel as enabled initially.
+  fake_bridge_->CreateChannel("https://example.com", true);
 
-    // Observer should be notified on first invocation of GetRuleIterator.
-    EXPECT_CALL(
-        mock_observer,
-        OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
-    EXPECT_CALL(check, Call("1: GetRuleIterator()"));
-
-    // Continue to report channel as enabled.
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
-
-    // Observer should not be notified this time.
-    EXPECT_CALL(check, Call("2: GetRuleIterator()"));
-
-    // Now report channel as blocked.
-    channels[0].status = NotificationChannelStatus::BLOCKED;
-    EXPECT_CALL(*mock_bridge_, GetChannels()).WillOnce(Return(channels));
-
-    // GetRuleIterator should now notify observer.
-    EXPECT_CALL(
-        mock_observer,
-        OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
-    EXPECT_CALL(check, Call("3: GetRuleIterator()"));
-  }
-
-  check.Call("0: GetRuleIterator never called");
+  // Observer should be notified on first invocation of GetRuleIterator.
+  EXPECT_CALL(
+      mock_observer,
+      OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("1: GetRuleIterator()");
+
+  // Observer should not be notified the second time.
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("2: GetRuleIterator()");
+
+  // Now emulate user blocking the channel.
+  fake_bridge_->SetChannelStatus("https://example.com",
+                                 NotificationChannelStatus::BLOCKED);
+  // GetRuleIterator should now notify observer.
+  EXPECT_CALL(
+      mock_observer,
+      OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
   channels_provider_->GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                       std::string(), false /* incognito */);
   content::RunAllBlockingPoolTasksUntilIdle();
-  check.Call("3: GetRuleIterator()");
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
@@ -297,7 +330,6 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  EXPECT_CALL(*mock_bridge_, CreateChannel(kTestOrigin, true /* enabled */));
   EXPECT_CALL(
       mock_observer,
       OnContentSettingChanged(_, _, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ""));
@@ -313,27 +345,33 @@
   content_settings::MockObserver mock_observer;
   channels_provider_->AddObserver(&mock_observer);
 
-  std::vector<NotificationChannel> channels;
-  channels.emplace_back("https://abc.com", NotificationChannelStatus::ENABLED);
-  channels.emplace_back("https://xyz.com", NotificationChannelStatus::BLOCKED);
-  ON_CALL(*mock_bridge_, GetChannels()).WillByDefault(Return(channels));
+  // Set up some channels.
+  fake_bridge_->SetChannelStatus("https://abc.com",
+                                 NotificationChannelStatus::ENABLED);
+  fake_bridge_->SetChannelStatus("https://xyz.com",
+                                 NotificationChannelStatus::BLOCKED);
 
-  EXPECT_CALL(*mock_bridge_, DeleteChannel("https://abc.com"));
-  EXPECT_CALL(*mock_bridge_, DeleteChannel("https://xyz.com"));
   EXPECT_CALL(mock_observer,
               OnContentSettingChanged(
                   ContentSettingsPattern(), ContentSettingsPattern(),
                   CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()));
+
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+
+  // Check channels were deleted.
+  EXPECT_EQ(0u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        ClearAllContentSettingsRulesNoopsForUnrelatedContentSettings) {
   InitChannelsProvider(true /* should_use_channels */);
 
-  EXPECT_CALL(*mock_bridge_, GetChannels()).Times(0);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(_)).Times(0);
+  // Set up some channels.
+  fake_bridge_->SetChannelStatus("https://abc.com",
+                                 NotificationChannelStatus::ENABLED);
+  fake_bridge_->SetChannelStatus("https://xyz.com",
+                                 NotificationChannelStatus::BLOCKED);
 
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_COOKIES);
@@ -341,15 +379,14 @@
       CONTENT_SETTINGS_TYPE_JAVASCRIPT);
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_GEOLOCATION);
+
+  // Check the channels still exist.
+  EXPECT_EQ(2u, fake_bridge_->GetChannels().size());
 }
 
 TEST_F(NotificationChannelsProviderAndroidTest,
        ClearAllContentSettingsRulesNoopsIfNotUsingChannels) {
   InitChannelsProvider(false /* should_use_channels */);
-
-  EXPECT_CALL(*mock_bridge_, GetChannels()).Times(0);
-  EXPECT_CALL(*mock_bridge_, DeleteChannel(_)).Times(0);
-
   channels_provider_->ClearAllContentSettingsRules(
       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
 }
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 a3f69e7..1c940336 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "chrome/browser/domain_reliability/service_factory.h"
 #include "chrome/browser/download/download_core_service_factory.h"
+#include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
@@ -224,6 +225,7 @@
   dom_distiller::DomDistillerServiceFactory::GetInstance();
   domain_reliability::DomainReliabilityServiceFactory::GetInstance();
   DownloadCoreServiceFactory::GetInstance();
+  DownloadServiceFactory::GetInstance();
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   EasyUnlockServiceFactory::GetInstance();
   EnhancedBookmarkKeyServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/chromeos/compiled_resources2.gyp b/chrome/browser/resources/chromeos/compiled_resources2.gyp
index 27fac69..c00877f 100644
--- a/chrome/browser/resources/chromeos/compiled_resources2.gyp
+++ b/chrome/browser/resources/chromeos/compiled_resources2.gyp
@@ -53,6 +53,7 @@
           '../chromeos/keyboard/keyboard_utils.js',
           '<(DEPTH)/ui/webui/resources/js/i18n_behavior.js',
           '<(DEPTH)/ui/webui/resources/js/web_ui_listener_behavior.js',
+          '../settings/page_visibility.js',
           '../settings/route.js',
           '../settings/people_page/easy_unlock_browser_proxy.js',
           '../settings/people_page/fingerprint_browser_proxy.js',
@@ -147,6 +148,7 @@
           '../chromeos/keyboard/keyboard_utils.js',
           '<(DEPTH)/ui/webui/resources/js/i18n_behavior.js',
           '<(DEPTH)/ui/webui/resources/js/web_ui_listener_behavior.js',
+          '../settings/page_visibility.js',
           '../settings/route.js',
           '../settings/people_page/easy_unlock_browser_proxy.js',
           '../settings/people_page/fingerprint_browser_proxy.js',
diff --git a/chrome/browser/resources/help/compiled_resources2.gyp b/chrome/browser/resources/help/compiled_resources2.gyp
index cbf5e3f..c0ae4e7 100644
--- a/chrome/browser/resources/help/compiled_resources2.gyp
+++ b/chrome/browser/resources/help/compiled_resources2.gyp
@@ -53,6 +53,7 @@
           '../chromeos/keyboard/keyboard_utils.js',
           '<(DEPTH)/ui/webui/resources/js/i18n_behavior.js',
           '<(DEPTH)/ui/webui/resources/js/web_ui_listener_behavior.js',
+          '../settings/page_visibility.js',
           '../settings/route.js',
           '../settings/people_page/easy_unlock_browser_proxy.js',
           '../settings/people_page/fingerprint_browser_proxy.js',
diff --git a/chrome/browser/resources/options/compiled_resources2.gyp b/chrome/browser/resources/options/compiled_resources2.gyp
index a9a64f9..50ff2da5 100644
--- a/chrome/browser/resources/options/compiled_resources2.gyp
+++ b/chrome/browser/resources/options/compiled_resources2.gyp
@@ -57,6 +57,7 @@
           '../chromeos/keyboard/keyboard_utils.js',
           '<(DEPTH)/ui/webui/resources/js/i18n_behavior.js',
           '<(DEPTH)/ui/webui/resources/js/web_ui_listener_behavior.js',
+          '../settings/page_visibility.js',
           '../settings/route.js',
           '../settings/people_page/easy_unlock_browser_proxy.js',
           '../settings/people_page/fingerprint_browser_proxy.js',
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index f2faf3f..0980850e 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -12,10 +12,12 @@
    *     destinations.
    * @param {!print_preview.UserInfo} userInfo User information repository.
    * @param {!print_preview.AppState} appState Application state.
+   * @param {!WebUIListenerTracker} listenerTracker Tracker for WebUI listeners
+   *     added in DestinationStore constructor.
    * @constructor
    * @extends {cr.EventTarget}
    */
-  function DestinationStore(nativeLayer, userInfo, appState) {
+  function DestinationStore(nativeLayer, userInfo, appState, listenerTracker) {
     cr.EventTarget.call(this);
 
     /**
@@ -177,8 +179,9 @@
     this.useSystemDefaultAsDefault_ =
         loadTimeData.getBoolean('useSystemDefaultPrinter');
 
-    this.addEventListeners_();
     this.reset_();
+
+    this.addWebUIEventListeners_(listenerTracker);
   }
 
   /**
@@ -546,6 +549,23 @@
     },
 
     /**
+     * Starts listening for relevant WebUI events and adds the listeners to
+     * |listenerTracker|. |listenerTracker| is responsible for removing the
+     * listeners when necessary.
+     * @param {!WebUIListenerTracker} listenerTracker
+     * @private
+     */
+    addWebUIEventListeners_: function(listenerTracker) {
+      listenerTracker.add(
+          'privet-printer-added', this.onPrivetPrinterAdded_.bind(this));
+      listenerTracker.add(
+          'extension-printers-added',
+          this.onExtensionPrintersAdded_.bind(this));
+      listenerTracker.add(
+          'reload-printer-list', this.onDestinationsReload.bind(this));
+    },
+
+    /**
      * Initializes the destination store. Sets the initially selected
      * destination. If any inserted destinations match this ID, that destination
      * will be automatically selected. This method must be called after the
@@ -864,6 +884,7 @@
      *     to set.
      */
     setCloudPrintInterface: function(cloudPrintInterface) {
+      assert(this.cloudPrintInterface_ == null);
       this.cloudPrintInterface_ = cloudPrintInterface;
       this.tracker_.add(
           this.cloudPrintInterface_,
@@ -1179,8 +1200,8 @@
      * @param {?print_preview.Destination} destination Information about the
      *     destination if it was resolved successfully.
      */
-    dispatchProvisionalDestinationResolvedEvent_: function(provisionalId,
-                                                           destination) {
+    dispatchProvisionalDestinationResolvedEvent_: function(
+        provisionalId, destination) {
       var event = new Event(
           DestinationStore.EventType.PROVISIONAL_DESTINATION_RESOLVED);
       event.provisionalId = provisionalId;
@@ -1333,18 +1354,6 @@
     },
 
     /**
-     * Binds handlers to events.
-     * @private
-     */
-    addEventListeners_: function() {
-      var nativeLayerEventTarget = this.nativeLayer_.getEventTarget();
-      this.tracker_.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.DESTINATIONS_RELOAD,
-          this.onDestinationsReload_.bind(this));
-    },
-
-    /**
      * Creates a local PDF print destination.
      * @private
      */
@@ -1549,7 +1558,7 @@
       if (printer.serviceName == this.waitForRegisterDestination_ &&
           !printer.isUnregistered) {
         this.waitForRegisterDestination_ = null;
-        this.onDestinationsReload_();
+        this.onDestinationsReload();
       } else {
         this.insertDestinations_(
             print_preview.PrivetDestinationParser.parse(printer));
@@ -1617,11 +1626,10 @@
     },
 
     /**
-     * Called from native layer after the user was requested to sign in, and did
-     * so successfully.
-     * @private
+     * Called from print preview after the user was requested to sign in, and
+     * did so successfully.
      */
-    onDestinationsReload_: function() {
+    onDestinationsReload: function() {
       this.reset_();
       this.autoSelectMatchingDestination_ =
           this.convertPreselectedToDestinationMatch_();
diff --git a/chrome/browser/resources/print_preview/data/invitation_store.js b/chrome/browser/resources/print_preview/data/invitation_store.js
index cbf037f..41f654fa 100644
--- a/chrome/browser/resources/print_preview/data/invitation_store.js
+++ b/chrome/browser/resources/print_preview/data/invitation_store.js
@@ -101,6 +101,7 @@
      *     to set.
      */
     setCloudPrintInterface: function(cloudPrintInterface) {
+      assert(this.cloudPrintInterface_ == null);
       this.cloudPrintInterface_ = cloudPrintInterface;
       this.tracker_.add(
           this.cloudPrintInterface_,
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js
index d0b37df..f3872db 100644
--- a/chrome/browser/resources/print_preview/native_layer.js
+++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -85,19 +85,6 @@
    * @constructor
    */
   function NativeLayer() {
-    // Bind global handlers
-    global.reloadPrintersList = this.onReloadPrintersList_.bind(this);
-    global.onDidGetDefaultPageLayout =
-        this.onDidGetDefaultPageLayout_.bind(this);
-    global.onDidGetPreviewPageCount = this.onDidGetPreviewPageCount_.bind(this);
-    global.onDidPreviewPage = this.onDidPreviewPage_.bind(this);
-    global.onEnableManipulateSettingsForTest =
-        this.onEnableManipulateSettingsForTest_.bind(this);
-    global.printPresetOptionsFromDocument =
-        this.onPrintPresetOptionsFromDocument_.bind(this);
-
-    /** @private {!cr.EventTarget} */
-    this.eventTarget_ = new cr.EventTarget();
   }
 
   /** @private {?print_preview.NativeLayer} */
@@ -122,27 +109,6 @@
   };
 
   /**
-   * Event types dispatched from the Chromium native layer.
-   * @enum {string}
-   * @const
-   */
-  NativeLayer.EventType = {
-    DESTINATIONS_RELOAD: 'print_preview.NativeLayer.DESTINATIONS_RELOAD',
-    DISABLE_SCALING: 'print_preview.NativeLayer.DISABLE_SCALING',
-    MANIPULATE_SETTINGS_FOR_TEST:
-        'print_preview.NativeLayer.MANIPULATE_SETTINGS_FOR_TEST',
-    PAGE_COUNT_READY: 'print_preview.NativeLayer.PAGE_COUNT_READY',
-    PAGE_LAYOUT_READY: 'print_preview.NativeLayer.PAGE_LAYOUT_READY',
-    PAGE_PREVIEW_READY: 'print_preview.NativeLayer.PAGE_PREVIEW_READY',
-    PREVIEW_GENERATION_DONE:
-        'print_preview.NativeLayer.PREVIEW_GENERATION_DONE',
-    PREVIEW_GENERATION_FAIL:
-        'print_preview.NativeLayer.PREVIEW_GENERATION_FAIL',
-    SETTINGS_INVALID: 'print_preview.NativeLayer.SETTINGS_INVALID',
-    PRINT_PRESET_OPTIONS: 'print_preview.NativeLayer.PRINT_PRESET_OPTIONS',
-  };
-
-  /**
    * Constant values matching printing::DuplexMode enum.
    * @enum {number}
    */
@@ -164,11 +130,6 @@
   NativeLayer.SERIALIZED_STATE_VERSION_ = 1;
 
   NativeLayer.prototype = {
-    /** @return {!cr.EventTarget} The event target for the native layer.*/
-    getEventTarget: function() {
-      return this.eventTarget_;
-    },
-
     /**
      * Requests access token for cloud print requests.
      * @param {string} authType type of access token.
@@ -314,13 +275,12 @@
     },
 
     /**
-     * Requests that a preview be generated. The following events may be
-     * dispatched in response:
-     *   - PAGE_COUNT_READY
-     *   - PAGE_LAYOUT_READY
-     *   - PAGE_PREVIEW_READY
-     *   - PREVIEW_GENERATION_DONE
-     *   - PREVIEW_GENERATION_FAIL
+     * Requests that a preview be generated. The following Web UI events may
+     * be triggered in response:
+     *   'print-preset-options',
+     *   'page-count-ready',
+     *   'page-layout-ready',
+     *   'page-preview-ready'
      * @param {!print_preview.Destination} destination Destination to print to.
      * @param {!print_preview.PrintTicketStore} printTicketStore Used to get the
      *     state of the print ticket.
@@ -526,9 +486,11 @@
      *     will be dispatched in response.
      * @param {boolean} addAccount Whether to open an 'add a new account' or
      *     default sign in page.
+     * @return {!Promise} Promise that resolves when the sign in tab has been
+     *     closed and the destinations should be reloaded.
      */
-    startCloudPrintSignIn: function(addAccount) {
-      chrome.send('signIn', [addAccount]);
+    signIn: function(addAccount) {
+      return cr.sendWithPromise('signIn', addAccount);
     },
 
     /** Navigates the user to the system printer settings interface. */
@@ -551,116 +513,13 @@
       chrome.send('forceOpenNewTab', [url]);
     },
 
-    /** Reloads the printer list. */
-    onReloadPrintersList_: function() {
-      cr.dispatchSimpleEvent(
-          this.eventTarget_, NativeLayer.EventType.DESTINATIONS_RELOAD);
-    },
-
-    /**
-     * @param {{contentWidth: number, contentHeight: number, marginLeft: number,
-     *          marginRight: number, marginTop: number, marginBottom: number,
-     *          printableAreaX: number, printableAreaY: number,
-     *          printableAreaWidth: number, printableAreaHeight: number}}
-     *          pageLayout Specifies default page layout details in points.
-     * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed
-     *     document has a custom page size style.
-     * @private
-     */
-    onDidGetDefaultPageLayout_: function(pageLayout, hasCustomPageSizeStyle) {
-      var pageLayoutChangeEvent =
-          new Event(NativeLayer.EventType.PAGE_LAYOUT_READY);
-      pageLayoutChangeEvent.pageLayout = pageLayout;
-      pageLayoutChangeEvent.hasCustomPageSizeStyle = hasCustomPageSizeStyle;
-      this.eventTarget_.dispatchEvent(pageLayoutChangeEvent);
-    },
-
-    /**
-     * Update the page count and check the page range.
-     * Called from PrintPreviewUI::OnDidGetPreviewPageCount().
-     * @param {number} pageCount The number of pages.
-     * @param {number} previewResponseId The preview request id that resulted in
-     *      this response.
-     * @param {number} fitToPageScaling The scaling percentage required to fit
-     *      the document to page, rounded to the nearest integer.
-     * @private
-     */
-    onDidGetPreviewPageCount_: function(
-        pageCount, previewResponseId, fitToPageScaling) {
-      var pageCountChangeEvent =
-          new Event(NativeLayer.EventType.PAGE_COUNT_READY);
-      pageCountChangeEvent.pageCount = pageCount;
-      pageCountChangeEvent.previewResponseId = previewResponseId;
-      pageCountChangeEvent.fitToPageScaling = fitToPageScaling;
-      this.eventTarget_.dispatchEvent(pageCountChangeEvent);
-    },
-
-    /**
-     * Notification that a print preview page has been rendered.
-     * Check if the settings have changed and request a regeneration if needed.
-     * Called from PrintPreviewUI::OnDidPreviewPage().
-     * @param {number} pageNumber The page number, 0-based.
-     * @param {number} previewUid Preview unique identifier.
-     * @param {number} previewResponseId The preview request id that resulted in
-     *     this response.
-     * @private
-     */
-    onDidPreviewPage_: function(pageNumber, previewUid, previewResponseId) {
-      var pagePreviewGenEvent =
-          new Event(NativeLayer.EventType.PAGE_PREVIEW_READY);
-      pagePreviewGenEvent.pageIndex = pageNumber;
-      pagePreviewGenEvent.previewUid = previewUid;
-      pagePreviewGenEvent.previewResponseId = previewResponseId;
-      this.eventTarget_.dispatchEvent(pagePreviewGenEvent);
-    },
-
-    /**
-     * Updates print preset options from source PDF document.
-     * Called from PrintPreviewUI::OnSetOptionsFromDocument().
-     * @param {{disableScaling: boolean, copies: number,
-     *          duplex: number}} options Specifies
-     *     printing options according to source document presets.
-     * @private
-     */
-    onPrintPresetOptionsFromDocument_: function(options) {
-      var printPresetOptionsEvent =
-          new Event(NativeLayer.EventType.PRINT_PRESET_OPTIONS);
-      printPresetOptionsEvent.optionsFromDocument = options;
-      this.eventTarget_.dispatchEvent(printPresetOptionsEvent);
-    },
-
-    /**
-     * Allows for onManipulateSettings to be called
-     * from the native layer.
-     * @private
-     */
-    onEnableManipulateSettingsForTest_: function() {
-      global.onManipulateSettingsForTest =
-          this.onManipulateSettingsForTest_.bind(this);
-    },
-
-    /**
-     * Dispatches an event to print_preview.js to change
-     * a particular setting for print preview.
-     * @param {!print_preview.PreviewSettings} settings Object containing the
-     *     value to be changed and that value should be set to.
-     * @private
-     */
-    onManipulateSettingsForTest_: function(settings) {
-      var manipulateSettingsEvent =
-          new Event(NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST);
-      manipulateSettingsEvent.settings = settings;
-      this.eventTarget_.dispatchEvent(manipulateSettingsEvent);
-    },
-
     /**
      * Sends a message to the test, letting it know that an
      * option has been set to a particular value and that the change has
      * finished modifying the preview area.
      */
     previewReadyForTest: function() {
-      if (global.onManipulateSettingsForTest)
-        chrome.send('UILoadedForTest');
+      chrome.send('UILoadedForTest');
     },
 
     /**
@@ -668,8 +527,7 @@
      * had not been changed successfully.
      */
     previewFailedForTest: function() {
-      if (global.onManipulateSettingsForTest)
-        chrome.send('UIFailedLoadingForTest');
+      chrome.send('UIFailedLoadingForTest');
     }
   };
 
diff --git a/chrome/browser/resources/print_preview/preview_generator.js b/chrome/browser/resources/print_preview/preview_generator.js
index 9880330..f8c06cf 100644
--- a/chrome/browser/resources/print_preview/preview_generator.js
+++ b/chrome/browser/resources/print_preview/preview_generator.js
@@ -14,11 +14,14 @@
    * @param {!print_preview.NativeLayer} nativeLayer Used to communicate to
    *     Chromium's preview rendering system.
    * @param {!print_preview.DocumentInfo} documentInfo Document data model.
+   * @param {!WebUIListenerTracker} listenerTracker Tracker for the WebUI
+   *     listeners added in the PreviewGenerator constructor.
    * @constructor
    * @extends {cr.EventTarget}
    */
   function PreviewGenerator(
-      destinationStore, printTicketStore, nativeLayer, documentInfo) {
+      destinationStore, printTicketStore, nativeLayer, documentInfo,
+      listenerTracker) {
     cr.EventTarget.call(this);
 
     /**
@@ -136,14 +139,7 @@
      */
     this.selectedDestination_ = null;
 
-    /**
-     * Event tracker used to keep track of native layer events.
-     * @type {!EventTracker}
-     * @private
-     */
-    this.tracker_ = new EventTracker();
-
-    this.addEventListeners_();
+    this.addWebUIEventListeners_(listenerTracker);
   }
 
   /**
@@ -171,6 +167,22 @@
     __proto__: cr.EventTarget.prototype,
 
     /**
+     * Starts listening for relevant WebUI events and adds the listeners to
+     * |listenerTracker|. |listenerTracker| is responsible for removing the
+     * listeners when necessary.
+     * @param {!WebUIListenerTracker} listenerTracker
+     * @private
+     */
+    addWebUIEventListeners_: function(listenerTracker) {
+      listenerTracker.add(
+          'page-count-ready', this.onPageCountReady_.bind(this));
+      listenerTracker.add(
+          'page-layout-ready', this.onPageLayoutReady_.bind(this));
+      listenerTracker.add(
+          'page-preview-ready', this.onPagePreviewReady_.bind(this));
+    },
+
+    /**
      * Request that new preview be generated. A preview request will not be
      * generated if the print ticket has not changed sufficiently.
      * @return {{id: number,
@@ -216,31 +228,6 @@
       };
     },
 
-    /** Removes all event listeners that the preview generator has attached. */
-    removeEventListeners: function() {
-      this.tracker_.removeAll();
-    },
-
-    /**
-     * Adds event listeners to the relevant native layer events.
-     * @private
-     */
-    addEventListeners_: function() {
-      var nativeLayerEventTarget = this.nativeLayer_.getEventTarget();
-      this.tracker_.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.PAGE_LAYOUT_READY,
-          this.onPageLayoutReady_.bind(this));
-      this.tracker_.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.PAGE_COUNT_READY,
-          this.onPageCountReady_.bind(this));
-      this.tracker_.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.PAGE_PREVIEW_READY,
-          this.onPagePreviewReady_.bind(this));
-    },
-
     /**
      * Dispatches a PAGE_READY event to signal that a page preview is ready.
      * @param {number} previewIndex Index of the page with respect to the pages
@@ -322,70 +309,86 @@
     /**
      * Called when the page layout of the document is ready. Always occurs
      * as a result of a preview request.
-     * @param {Event} event Contains layout info about the document.
+     * @param {{marginTop: number,
+     *          marginLeft: number,
+     *          marginBottom: number,
+     *          marginRight: number,
+     *          contentWidth: number,
+     *          contentHeight: number,
+     *          printableAreaX: number,
+     *          printableAreaY: number,
+     *          printableAreaWidth: number,
+     *          printableAreaHeight: number,
+     *        }} pageLayout Layout information about the document.
+     * @param {boolean} hasCustomPageSizeStyle Whether this document has a
+     *     custom page size or style to use.
      * @private
      */
-    onPageLayoutReady_: function(event) {
+    onPageLayoutReady_: function(pageLayout, hasCustomPageSizeStyle) {
       // NOTE: A request ID is not specified, so assuming its for the current
       // in-flight request.
 
       var origin = new print_preview.Coordinate2d(
-          event.pageLayout.printableAreaX, event.pageLayout.printableAreaY);
+          pageLayout.printableAreaX, pageLayout.printableAreaY);
       var size = new print_preview.Size(
-          event.pageLayout.printableAreaWidth,
-          event.pageLayout.printableAreaHeight);
+          pageLayout.printableAreaWidth, pageLayout.printableAreaHeight);
 
       var margins = new print_preview.Margins(
-          Math.round(event.pageLayout.marginTop),
-          Math.round(event.pageLayout.marginRight),
-          Math.round(event.pageLayout.marginBottom),
-          Math.round(event.pageLayout.marginLeft));
+          Math.round(pageLayout.marginTop), Math.round(pageLayout.marginRight),
+          Math.round(pageLayout.marginBottom),
+          Math.round(pageLayout.marginLeft));
 
       var o = print_preview.ticket_items.CustomMarginsOrientation;
       var pageSize = new print_preview.Size(
-          event.pageLayout.contentWidth + margins.get(o.LEFT) +
-              margins.get(o.RIGHT),
-          event.pageLayout.contentHeight + margins.get(o.TOP) +
+          pageLayout.contentWidth + margins.get(o.LEFT) + margins.get(o.RIGHT),
+          pageLayout.contentHeight + margins.get(o.TOP) +
               margins.get(o.BOTTOM));
 
       this.documentInfo_.updatePageInfo(
           new print_preview.PrintableArea(origin, size), pageSize,
-          event.hasCustomPageSizeStyle, margins);
+          hasCustomPageSizeStyle, margins);
     },
 
     /**
      * Called when the document page count is received from the native layer.
      * Always occurs as a result of a preview request.
-     * @param {Event} event Contains the document's page count.
+     * @param {number} pageCount The document's page count.
+     * @param {number} previewResponseId The request ID that corresponds to this
+     *     page count.
+     * @param {number} fitToPageScaling The scaling required to fit the document
+     *     to page (unused).
      * @private
      */
-    onPageCountReady_: function(event) {
-      if (this.inFlightRequestId_ != event.previewResponseId) {
+    onPageCountReady_: function(
+        pageCount, previewResponseId, fitToPageScaling) {
+      if (this.inFlightRequestId_ != previewResponseId) {
         return;  // Ignore old response.
       }
-      this.documentInfo_.updatePageCount(event.pageCount);
+      this.documentInfo_.updatePageCount(pageCount);
       this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges();
     },
 
     /**
      * Called when a page's preview has been generated. Dispatches a
      * PAGE_READY event.
-     * @param {Event} event Contains the page index and preview UID.
+     * @param {number} pageIndex The index of the page whose preview is ready.
+     * @param {number} previewUid The unique ID of the print preview UI.
+     * @param {number} previewResponseId The preview request ID that this page
+     *     preview is a response to.
      * @private
      */
-    onPagePreviewReady_: function(event) {
-      if (this.inFlightRequestId_ != event.previewResponseId) {
+    onPagePreviewReady_: function(pageIndex, previewUid, previewResponseId) {
+      if (this.inFlightRequestId_ != previewResponseId) {
         return;  // Ignore old response.
       }
-      var pageNumber = event.pageIndex + 1;
+      var pageNumber = pageIndex + 1;
       var pageNumberSet = this.printTicketStore_.pageRange.getPageNumberSet();
       if (pageNumberSet.hasPageNumber(pageNumber)) {
         var previewIndex = pageNumberSet.getPageNumberIndex(pageNumber);
         if (previewIndex == 0) {
-          this.dispatchPreviewStartEvent_(event.previewUid, event.pageIndex);
+          this.dispatchPreviewStartEvent_(previewUid, pageIndex);
         }
-        this.dispatchPageReadyEvent_(
-            previewIndex, pageNumber, event.previewUid);
+        this.dispatchPageReadyEvent_(previewIndex, pageNumber, previewUid);
       }
     },
 
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js
index 0e2ff3c..536c62d4 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.js
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -344,7 +344,7 @@
       if (this.checkPluginCompatibility_()) {
         this.previewGenerator_ = new print_preview.PreviewGenerator(
             this.destinationStore_, this.printTicketStore_, this.nativeLayer_,
-            this.documentInfo_);
+            this.documentInfo_, this.listenerTracker);
         this.tracker.add(
             this.previewGenerator_,
             print_preview.PreviewGenerator.EventType.PREVIEW_START,
@@ -365,9 +365,6 @@
     /** @override */
     exitDocument: function() {
       print_preview.Component.prototype.exitDocument.call(this);
-      if (this.previewGenerator_) {
-        this.previewGenerator_.removeEventListeners();
-      }
       this.overlayEl_ = null;
       this.openSystemDialogButton_ = null;
     },
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index c60a439..cb37122f 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -84,7 +84,8 @@
      * @private
      */
     this.destinationStore_ = new print_preview.DestinationStore(
-        this.nativeLayer_, this.userInfo_, this.appState_);
+        this.nativeLayer_, this.userInfo_, this.appState_,
+        this.listenerTracker);
 
     /**
      * Data store which holds printer sharing invitations.
@@ -310,6 +311,13 @@
      * @private
      */
     this.showSystemDialogBeforeNextPrint_ = false;
+
+    /**
+     * Whether the preview is listening for the manipulate-settings-for-test
+     * UI event.
+     * @private {boolean}
+     */
+    this.isListeningForManipulateSettings_ = false;
   }
 
   PrintPreview.prototype = {
@@ -333,34 +341,19 @@
       cr.ui.FocusOutlineManager.forDocument(document);
       this.listenerTracker.add('print-failed', this.onPrintFailed_.bind(this));
       this.listenerTracker.add(
-          'privet-printer-added',
-          this.destinationStore_.onPrivetPrinterAdded_.bind(
-              this.destinationStore_));
-      this.listenerTracker.add(
-          'extension-printers-added',
-          this.destinationStore_.onExtensionPrintersAdded_.bind(
-              this.destinationStore_));
-      this.listenerTracker.add(
           'use-cloud-print', this.onCloudPrintEnable_.bind(this));
+      this.listenerTracker.add(
+          'print-preset-options',
+          this.onPrintPresetOptionsFromDocument_.bind(this));
+      this.listenerTracker.add(
+          'preview-page-count', this.onPageCountReady_.bind(this));
+      this.listenerTracker.add(
+          'enable-manipulate-settings-for-test',
+          this.onEnableManipulateSettingsForTest_.bind(this));
     },
 
     /** @override */
     enterDocument: function() {
-      // Native layer events.
-      var nativeLayerEventTarget = this.nativeLayer_.getEventTarget();
-      this.tracker.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS,
-          this.onPrintPresetOptionsFromDocument_.bind(this));
-      this.tracker.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.PAGE_COUNT_READY,
-          this.onPageCountReady_.bind(this));
-      this.tracker.add(
-          nativeLayerEventTarget,
-          print_preview.NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST,
-          this.onManipulateSettingsForTest_.bind(this));
-
       if ($('system-dialog-link')) {
         this.tracker.add(
             getRequiredElement('system-dialog-link'), 'click',
@@ -824,7 +817,8 @@
     onPreviewGenerationDone_: function() {
       this.isPreviewGenerationInProgress_ = false;
       this.printHeader_.isPrintButtonEnabled = true;
-      this.nativeLayer_.previewReadyForTest();
+      if (this.isListeningForManipulateSettings_)
+        this.nativeLayer_.previewReadyForTest();
       this.printIfReady_();
     },
 
@@ -1002,41 +996,46 @@
      * @private
      */
     onCloudPrintSignInActivated_: function(addAccount) {
-      this.nativeLayer_.startCloudPrintSignIn(addAccount);
+      this.nativeLayer_.signIn(addAccount)
+          .then(this.destinationStore_.onDestinationsReload.bind(
+              this.destinationStore_));
     },
 
     /**
      * Updates printing options according to source document presets.
-     * @param {Event} event Contains options from source document.
+     * @param {boolean} disableScaling Whether the document disables scaling.
+     * @param {number} copies The default number of copies from the document.
+     * @param {number} duplex The default duplex setting from the document.
      * @private
      */
-    onPrintPresetOptionsFromDocument_: function(event) {
-      if (event.optionsFromDocument.disableScaling)
+    onPrintPresetOptionsFromDocument_: function(
+        disableScaling, copies, duplex) {
+      if (disableScaling)
         this.documentInfo_.updateIsScalingDisabled(true);
 
-      if (event.optionsFromDocument.copies > 0 &&
-          this.printTicketStore_.copies.isCapabilityAvailable()) {
-        this.printTicketStore_.copies.updateValue(
-            event.optionsFromDocument.copies);
+      if (copies > 0 && this.printTicketStore_.copies.isCapabilityAvailable()) {
+        this.printTicketStore_.copies.updateValue(copies);
       }
 
-      if (event.optionsFromDocument.duplex >= 0 &&
-          this.printTicketStore_.duplex.isCapabilityAvailable()) {
-        this.printTicketStore_.duplex.updateValue(
-            event.optionsFromDocument.duplex);
+      if (duplex >= 0 & this.printTicketStore_.duplex.isCapabilityAvailable()) {
+        this.printTicketStore_.duplex.updateValue(duplex);
       }
     },
 
     /**
      * Called when the Page Count Ready message is received to update the fit to
      * page scaling value in the scaling settings.
-     * @param {Event} event Event object representing the page count ready
-     *     message
+     * @param {number} pageCount The document's page count (unused).
+     * @param {number} previewResponseId The request ID that corresponds to this
+     *     page count (unused).
+     * @param {number} fitToPageScaling The scaling required to fit the document
+     *     to page.
      * @private
      */
-    onPageCountReady_: function(event) {
-      if (event.fitToPageScaling >= 0) {
-        this.scalingSettings_.updateFitToPageScaling(event.fitToPageScaling);
+    onPageCountReady_: function(
+        pageCount, previewResponseId, fitToPageScaling) {
+      if (fitToPageScaling >= 0) {
+        this.scalingSettings_.updateFitToPageScaling(fitToPageScaling);
       }
     },
 
@@ -1053,14 +1052,24 @@
     },
 
     /**
-     * Called when the print preview settings need to be changed for testing.
-     * @param {Event} event Event object that contains the option that is to
-     *     be changed and what to set that option.
+     * Called to start listening for the manipulate-settings-for-test WebUI
+     * event so that settings can be modified by this event.
      * @private
      */
-    onManipulateSettingsForTest_: function(event) {
-      var settings =
-          /** @type {print_preview.PreviewSettings} */ (event.settings);
+    onEnableManipulateSettingsForTest_: function() {
+      this.listenerTracker.add(
+          'manipulate-settings-for-test',
+          this.onManipulateSettingsForTest_.bind(this));
+      this.isListeningForManipulateSettings_ = true;
+    },
+
+    /**
+     * Called when the print preview settings need to be changed for testing.
+     * @param {!print_preview.PreviewSettings} settings Contains print preview
+     *     settings to change and the values to change them to.
+     * @private
+     */
+    onManipulateSettingsForTest_: function(settings) {
       if ('selectSaveAsPdfDestination' in settings) {
         this.saveAsPdfForTest_();  // No parameters.
       } else if ('layoutSettings' in settings) {
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js
index 99ecf4da..add54039 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -34,9 +34,11 @@
       value: function() {
         var map = new Map();
         // <if expr="chromeos">
-        map.set(
-            settings.Route.MANAGE_ACCESSIBILITY.path,
-            '#subpage-trigger .subpage-arrow');
+        if (settings.routes.MANAGE_ACCESSIBILITY) {
+          map.set(
+              settings.routes.MANAGE_ACCESSIBILITY.path,
+              '#subpage-trigger .subpage-arrow');
+        }
         // </if>
         return map;
       },
@@ -46,7 +48,7 @@
   // <if expr="chromeos">
   /** @private */
   onManageAccessibilityFeaturesTap_: function() {
-    settings.navigateTo(settings.Route.MANAGE_ACCESSIBILITY);
+    settings.navigateTo(settings.routes.MANAGE_ACCESSIBILITY);
   },
   // </if>
 });
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
index 3b711a0..79e39c1d 100644
--- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
@@ -83,28 +83,28 @@
   /** @private */
   onDisplayTap_: function() {
     settings.navigateTo(
-        settings.Route.DISPLAY,
+        settings.routes.DISPLAY,
         /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onAppearanceTap_: function() {
     settings.navigateTo(
-        settings.Route.APPEARANCE,
+        settings.routes.APPEARANCE,
         /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onKeyboardTap_: function() {
     settings.navigateTo(
-        settings.Route.KEYBOARD,
+        settings.routes.KEYBOARD,
         /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onMouseTap_: function() {
     settings.navigateTo(
-        settings.Route.POINTERS,
+        settings.routes.POINTERS,
         /* dynamicParams */ null, /* removeSearch */ true);
   },
 });
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index 2f61de74..c9842d5 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -81,9 +81,11 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(
-            settings.Route.DETAILED_BUILD_INFO.path,
-            '#detailed-build-info-trigger');
+        if (settings.routes.DETAILED_BUILD_INFO) {
+          map.set(
+              settings.routes.DETAILED_BUILD_INFO.path,
+              '#detailed-build-info-trigger');
+        }
         return map;
       },
     },
@@ -390,7 +392,7 @@
 
   /** @private */
   onDetailedBuildInfoTap_: function() {
-    settings.navigateTo(settings.Route.DETAILED_BUILD_INFO);
+    settings.navigateTo(settings.routes.DETAILED_BUILD_INFO);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_page.js b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
index b7e1491c..580849a 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
@@ -28,9 +28,11 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(
-            settings.Route.ANDROID_APPS_DETAILS.path,
-            '#android-apps .subpage-arrow');
+        if (settings.routes.ANDROID_APPS_DETAILS) {
+          map.set(
+              settings.routes.ANDROID_APPS_DETAILS.path,
+              '#android-apps .subpage-arrow');
+        }
         return map;
       },
     },
@@ -53,6 +55,6 @@
   /** @private */
   onSubpageTap_: function() {
     if (this.androidAppsInfo.playStoreEnabled)
-      settings.navigateTo(settings.Route.ANDROID_APPS_DETAILS);
+      settings.navigateTo(settings.routes.ANDROID_APPS_DETAILS);
   },
 });
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.js b/chrome/browser/resources/settings/appearance_page/appearance_page.js
index 9782c841..8b22e8f 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.js
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.js
@@ -107,9 +107,11 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(
-            settings.Route.FONTS.path,
-            '#customize-fonts-subpage-trigger .subpage-arrow');
+        if (settings.routes.FONTS) {
+          map.set(
+              settings.routes.FONTS.path,
+              '#customize-fonts-subpage-trigger .subpage-arrow');
+        }
         return map;
       },
     },
@@ -169,7 +171,7 @@
 
   /** @private */
   onCustomizeFontsTap_: function() {
-    settings.navigateTo(settings.Route.FONTS);
+    settings.navigateTo(settings.routes.FONTS);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index fe8cc862..1f386cc 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -115,7 +115,7 @@
   currentRouteChanged: function(newRoute, oldRoute) {
     this.currentRoute_ = newRoute;
 
-    if (settings.Route.ADVANCED.contains(newRoute))
+    if (settings.routes.ADVANCED && settings.routes.ADVANCED.contains(newRoute))
       this.advancedToggleExpanded = true;
 
     if (oldRoute && oldRoute.isSubpage()) {
@@ -258,7 +258,7 @@
    * @private
    */
   showBasicPage_: function(currentRoute, inSearchMode, hasExpandedSection) {
-    return !hasExpandedSection || settings.Route.BASIC.contains(currentRoute);
+    return !hasExpandedSection || settings.routes.BASIC.contains(currentRoute);
   },
 
   /**
@@ -272,8 +272,10 @@
    */
   showAdvancedPage_: function(
       currentRoute, inSearchMode, hasExpandedSection, advancedToggleExpanded) {
-    return hasExpandedSection ? settings.Route.ADVANCED.contains(currentRoute) :
-                                advancedToggleExpanded || inSearchMode;
+    return hasExpandedSection ?
+        (settings.routes.ADVANCED &&
+         settings.routes.ADVANCED.contains(currentRoute)) :
+        advancedToggleExpanded || inSearchMode;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index 104106c..35b5c439 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -70,9 +70,11 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(
-            settings.Route.BLUETOOTH_DEVICES.path,
-            '#bluetoothDevices .subpage-arrow');
+        if (settings.routes.BLUETOOTH_DEVICES) {
+          map.set(
+              settings.routes.BLUETOOTH_DEVICES.path,
+              '#bluetoothDevices .subpage-arrow');
+        }
         return map;
       },
     },
@@ -212,6 +214,6 @@
 
   /** @private */
   openSubpage_: function() {
-    settings.navigateTo(settings.Route.BLUETOOTH_DEVICES);
+    settings.navigateTo(settings.routes.BLUETOOTH_DEVICES);
   }
 });
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
index 6bfa037..731f9d52 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
@@ -240,7 +240,7 @@
   updateDiscovery_: function() {
     if (!this.adapterState || !this.adapterState.powered)
       return;
-    if (settings.getCurrentRoute() == settings.Route.BLUETOOTH_DEVICES)
+    if (settings.getCurrentRoute() == settings.routes.BLUETOOTH_DEVICES)
       this.startDiscovery_();
     else
       this.stopDiscovery_();
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index a3f4a15..f655815f 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -48,6 +48,7 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        'page_visibility'
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/device_page/device_page.js b/chrome/browser/resources/settings/device_page/device_page.js
index 44d61a6..47f6b67 100644
--- a/chrome/browser/resources/settings/device_page/device_page.js
+++ b/chrome/browser/resources/settings/device_page/device_page.js
@@ -57,12 +57,18 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(settings.Route.POINTERS.path, '#pointersRow .subpage-arrow');
-        map.set(settings.Route.KEYBOARD.path, '#keyboardRow .subpage-arrow');
-        map.set(settings.Route.STYLUS.path, '#stylusRow .subpage-arrow');
-        map.set(settings.Route.DISPLAY.path, '#displayRow .subpage-arrow');
-        map.set(settings.Route.STORAGE.path, '#storageRow .subpage-arrow');
-        map.set(settings.Route.POWER.path, '#powerRow .subpage-arrow');
+        if (settings.routes.POINTERS)
+          map.set(settings.routes.POINTERS.path, '#pointersRow .subpage-arrow');
+        if (settings.routes.KEYBOARD)
+          map.set(settings.routes.KEYBOARD.path, '#keyboardRow .subpage-arrow');
+        if (settings.routes.STYLUS)
+          map.set(settings.routes.STYLUS.path, '#stylusRow .subpage-arrow');
+        if (settings.routes.DISPLAY)
+          map.set(settings.routes.DISPLAY.path, '#displayRow .subpage-arrow');
+        if (settings.routes.STORAGE)
+          map.set(settings.routes.STORAGE.path, '#storageRow .subpage-arrow');
+        if (settings.routes.POWER)
+          map.set(settings.routes.POWER.path, '#powerRow .subpage-arrow');
         return map;
       },
     },
@@ -104,7 +110,7 @@
    * @private
    */
   onPointersTap_: function() {
-    settings.navigateTo(settings.Route.POINTERS);
+    settings.navigateTo(settings.routes.POINTERS);
   },
 
   /**
@@ -112,7 +118,7 @@
    * @private
    */
   onKeyboardTap_: function() {
-    settings.navigateTo(settings.Route.KEYBOARD);
+    settings.navigateTo(settings.routes.KEYBOARD);
   },
 
   /**
@@ -120,7 +126,7 @@
    * @private
    */
   onStylusTap_: function() {
-    settings.navigateTo(settings.Route.STYLUS);
+    settings.navigateTo(settings.routes.STYLUS);
   },
 
   /**
@@ -128,7 +134,7 @@
    * @private
    */
   onDisplayTap_: function() {
-    settings.navigateTo(settings.Route.DISPLAY);
+    settings.navigateTo(settings.routes.DISPLAY);
   },
 
   /**
@@ -136,7 +142,7 @@
    * @private
    */
   onStorageTap_: function() {
-    settings.navigateTo(settings.Route.STORAGE);
+    settings.navigateTo(settings.routes.STORAGE);
   },
 
   /**
@@ -144,7 +150,7 @@
    * @private
    */
   onPowerTap_: function() {
-    settings.navigateTo(settings.Route.POWER);
+    settings.navigateTo(settings.routes.POWER);
   },
 
   /** @protected */
@@ -169,8 +175,8 @@
   checkPointerSubpage_: function() {
     // Check that the properties have explicitly been set to false.
     if (this.hasMouse_ === false && this.hasTouchpad_ === false &&
-        settings.getCurrentRoute() == settings.Route.POINTERS) {
-      settings.navigateTo(settings.Route.DEVICE);
+        settings.getCurrentRoute() == settings.routes.POINTERS) {
+      settings.navigateTo(settings.routes.DEVICE);
     }
   },
 });
diff --git a/chrome/browser/resources/settings/device_page/keyboard.js b/chrome/browser/resources/settings/device_page/keyboard.js
index ed49f142..e10766d 100644
--- a/chrome/browser/resources/settings/device_page/keyboard.js
+++ b/chrome/browser/resources/settings/device_page/keyboard.js
@@ -129,6 +129,6 @@
   },
 
   onShowLanguageInputTap_: function() {
-    settings.navigateTo(settings.Route.LANGUAGES);
+    settings.navigateTo(settings.routes.LANGUAGES);
   },
 });
diff --git a/chrome/browser/resources/settings/device_page/storage.js b/chrome/browser/resources/settings/device_page/storage.js
index 47c52115d..0e592fc 100644
--- a/chrome/browser/resources/settings/device_page/storage.js
+++ b/chrome/browser/resources/settings/device_page/storage.js
@@ -107,7 +107,7 @@
    * @protected
    */
   currentRouteChanged: function() {
-    if (settings.getCurrentRoute() == settings.Route.STORAGE)
+    if (settings.getCurrentRoute() == settings.routes.STORAGE)
       this.onPageShown_();
   },
 
@@ -144,7 +144,7 @@
    * @private
    */
   onBrowsingDataTap_: function() {
-    settings.navigateTo(settings.Route.CLEAR_BROWSER_DATA);
+    settings.navigateTo(settings.routes.CLEAR_BROWSER_DATA);
   },
 
   /**
@@ -160,7 +160,7 @@
    * @private
    */
   onOtherUsersTap_: function() {
-    settings.navigateTo(settings.Route.ACCOUNTS);
+    settings.navigateTo(settings.routes.ACCOUNTS);
   },
 
   /**
@@ -247,7 +247,7 @@
     // We update the storage usage every 5 seconds.
     if (this.updateTimerId_ == -1) {
       this.updateTimerId_ = window.setInterval(function() {
-        if (settings.getCurrentRoute() != settings.Route.STORAGE) {
+        if (settings.getCurrentRoute() != settings.routes.STORAGE) {
           this.stopPeriodicUpdate_();
           return;
         }
diff --git a/chrome/browser/resources/settings/internet_page/internet_config.js b/chrome/browser/resources/settings/internet_page/internet_config.js
index 9f121e2b..4760b53a 100644
--- a/chrome/browser/resources/settings/internet_page/internet_config.js
+++ b/chrome/browser/resources/settings/internet_page/internet_config.js
@@ -193,7 +193,7 @@
    * @protected
    */
   currentRouteChanged: function(route) {
-    if (route != settings.Route.NETWORK_CONFIG)
+    if (route != settings.routes.NETWORK_CONFIG)
       return;
 
     this.propertiesSent_ = false;
@@ -222,7 +222,7 @@
 
   /** @private */
   close_: function() {
-    if (settings.getCurrentRoute() == settings.Route.NETWORK_CONFIG)
+    if (settings.getCurrentRoute() == settings.routes.NETWORK_CONFIG)
       settings.navigateToPreviousRoute();
   },
 
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 81b3add..cacec5c1 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -158,7 +158,7 @@
    * @protected
    */
   currentRouteChanged: function(route, oldRoute) {
-    if (route != settings.Route.NETWORK_DETAIL) {
+    if (route != settings.routes.NETWORK_DETAIL) {
       if (this.networksChangedListener_) {
         this.networkingPrivate.onNetworksChanged.removeListener(
             this.networksChangedListener_);
@@ -185,7 +185,7 @@
     this.shouldShowConfigureWhenNetworkLoaded_ =
         queryParams.get('showConfigure') == 'true';
     this.wasPreviousRouteNetworkDetailPage_ =
-        oldRoute == settings.Route.NETWORK_DETAIL;
+        oldRoute == settings.routes.NETWORK_DETAIL;
     var name = queryParams.get('name') || type;
     this.networkProperties = {
       GUID: this.guid,
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index a4d148e3..529d9c3 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -163,14 +163,14 @@
    * @protected
    */
   currentRouteChanged: function(route, oldRoute) {
-    if (route == settings.Route.INTERNET_NETWORKS) {
+    if (route == settings.routes.INTERNET_NETWORKS) {
       // Handle direct navigation to the networks page,
       // e.g. chrome://settings/internet/networks?type=WiFi
       var queryParams = settings.getQueryParameters();
       var type = queryParams.get('type');
       if (type)
         this.subpageType_ = type;
-    } else if (route == settings.Route.KNOWN_NETWORKS) {
+    } else if (route == settings.routes.KNOWN_NETWORKS) {
       // Handle direct navigation to the known networks page,
       // e.g. chrome://settings/internet/knownNetworks?type=WiFi
       var queryParams = settings.getQueryParameters();
@@ -178,17 +178,18 @@
       if (type)
         this.knownNetworksType_ = type;
     } else if (
-        route != settings.Route.INTERNET && route != settings.Route.BASIC) {
+        route != settings.routes.INTERNET && route != settings.routes.BASIC) {
       // If we are navigating to a non internet section, do not set focus.
       return;
     }
 
-    if (!settings.Route.INTERNET.contains(oldRoute))
+    if (!settings.routes.INTERNET ||
+        !settings.routes.INTERNET.contains(oldRoute))
       return;
 
     // Focus the subpage arrow where appropriate.
     var selector;
-    if (route == settings.Route.INTERNET_NETWORKS) {
+    if (route == settings.routes.INTERNET_NETWORKS) {
       // iron-list makes the correct timing to focus an item in the list
       // very complicated, and the item may not exist, so just focus the
       // entire list for now.
@@ -238,7 +239,7 @@
       params.append('guid', guid);
     if (name)
       params.append('name', name);
-    settings.navigateTo(settings.Route.NETWORK_CONFIG, params);
+    settings.navigateTo(settings.routes.NETWORK_CONFIG, params);
   },
 
   /**
@@ -252,7 +253,7 @@
     params.append('type', event.detail.Type);
     if (event.detail.Name)
       params.append('name', event.detail.Name);
-    settings.navigateTo(settings.Route.NETWORK_DETAIL, params);
+    settings.navigateTo(settings.routes.NETWORK_DETAIL, params);
   },
 
   /**
@@ -264,7 +265,7 @@
     var params = new URLSearchParams;
     params.append('type', event.detail.Type);
     this.subpageType_ = event.detail.Type;
-    settings.navigateTo(settings.Route.INTERNET_NETWORKS, params);
+    settings.navigateTo(settings.routes.INTERNET_NETWORKS, params);
   },
 
   /**
@@ -300,7 +301,7 @@
     var params = new URLSearchParams;
     params.append('type', event.detail.Type);
     this.knownNetworksType_ = event.detail.type;
-    settings.navigateTo(settings.Route.KNOWN_NETWORKS, params);
+    settings.navigateTo(settings.routes.KNOWN_NETWORKS, params);
   },
 
   /**
@@ -451,7 +452,7 @@
       params.append('name', CrOnc.getNetworkName(properties));
       params.append('showConfigure', true.toString());
 
-      settings.navigateTo(settings.Route.NETWORK_DETAIL, params);
+      settings.navigateTo(settings.routes.NETWORK_DETAIL, params);
       return;
     }
 
diff --git a/chrome/browser/resources/settings/internet_page/internet_shared_css.html b/chrome/browser/resources/settings/internet_page/internet_shared_css.html
index f4581f0..83858c7c 100644
--- a/chrome/browser/resources/settings/internet_page/internet_shared_css.html
+++ b/chrome/browser/resources/settings/internet_page/internet_shared_css.html
@@ -22,18 +22,6 @@
         margin-top: -9px;
       }
 
-      .button-container {
-        align-items: center;
-        display: flex;
-      }
-
-      .button-container paper-button {
-        /* Align text edge with trailing margin (12px button padding) */
-        -webkit-margin-end: -12px;
-        /* 8px spacing between highlight edges. */
-        -webkit-margin-start: calc(12px + 8px);
-      }
-
       .settings-box.indented {
         -webkit-margin-start: var(--settings-box-row-padding);
       }
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js
index 654097fe1..b8a1da98 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -119,7 +119,7 @@
    * @protected
    */
   currentRouteChanged: function(route) {
-    if (route != settings.Route.INTERNET_NETWORKS) {
+    if (route != settings.routes.INTERNET_NETWORKS) {
       this.stopScanning_();
       return;
     }
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.js b/chrome/browser/resources/settings/internet_page/network_proxy.js
index 1579b0b..52e7e02 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.js
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.js
@@ -131,7 +131,7 @@
   currentRouteChanged: function(newRoute) {
     this.proxyModified_ = false;
     this.proxy_ = this.createDefaultProxySettings_();
-    if (newRoute == settings.Route.NETWORK_DETAIL)
+    if (newRoute == settings.routes.NETWORK_DETAIL)
       this.updateProxy_();
   },
 
diff --git a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
index 592ff28..bfe73dbd 100644
--- a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
+++ b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
@@ -21,7 +21,7 @@
      */
     subpageRoute: {
       type: Object,
-      value: settings.Route.EDIT_DICTIONARY,
+      value: settings.routes.EDIT_DICTIONARY,
     },
 
     /** @private {!Array<string>} */
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index 0678644..3bdef9a0 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -67,14 +67,18 @@
       value: function() {
         var map = new Map();
         // <if expr="not is_macosx">
-        map.set(
-            settings.Route.EDIT_DICTIONARY.path,
-            '#spellCheckCollapse .subpage-arrow');
+        if (settings.routes.EDIT_DICTIONARY) {
+          map.set(
+              settings.routes.EDIT_DICTIONARY.path,
+              '#spellCheckCollapse .subpage-arrow');
+        }
         // </if>
         // <if expr="chromeos">
-        map.set(
-            settings.Route.INPUT_METHODS.path,
-            '#inputMethodsCollapse .subpage-arrow');
+        if (settings.routes.INPUT_METHODS) {
+          map.set(
+              settings.routes.INPUT_METHODS.path,
+              '#inputMethodsCollapse .subpage-arrow');
+        }
         // </if>
         return map;
       },
@@ -169,7 +173,7 @@
    * @private
    */
   onManageInputMethodsTap_: function() {
-    settings.navigateTo(settings.Route.INPUT_METHODS);
+    settings.navigateTo(settings.routes.INPUT_METHODS);
   },
 
   /**
@@ -421,7 +425,7 @@
    * @private
    */
   onEditDictionaryTap_: function() {
-    settings.navigateTo(settings.Route.EDIT_DICTIONARY);
+    settings.navigateTo(settings.routes.EDIT_DICTIONARY);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.js b/chrome/browser/resources/settings/on_startup_page/on_startup_page.js
index 70445ed2..38cdc3cc 100644
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.js
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.js
@@ -15,6 +15,6 @@
 
   /** @private */
   onManageStartupUrls_: function() {
-    settings.navigateTo(settings.Route.STARTUP_URLS);
+    settings.navigateTo(settings.routes.STARTUP_URLS);
   },
 });
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
index 02ab24e..e9ab6e80 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
@@ -62,10 +62,7 @@
 
   /** @override */
   attached: function() {
-    settings.OnStartupBrowserProxyImpl.getInstance().getNtpExtension().then(
-        function(ntpExtension) {
-          this.ntpExtension_ = ntpExtension;
-        }.bind(this));
+    this.getNtpExtension_();
 
     this.browserProxy_ = settings.StartupUrlsPageBrowserProxyImpl.getInstance();
     this.addWebUIListener('update-startup-pages', function(startupPages) {
@@ -86,6 +83,14 @@
     }.bind(this));
   },
 
+  /** @private */
+  getNtpExtension_: function() {
+    settings.OnStartupBrowserProxyImpl.getInstance().getNtpExtension().then(
+        function(ntpExtension) {
+          this.ntpExtension_ = ntpExtension;
+        }.bind(this));
+  },
+
   /**
    * @param {!Event} e
    * @private
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
index a5d4a1c1..68fb662 100644
--- a/chrome/browser/resources/settings/page_visibility.js
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -9,11 +9,11 @@
  *   appearance: (boolean|undefined|AppearancePageVisibility),
  *   dateTime: (boolean|undefined|DateTimePageVisibility),
  *   defaultBrowser: (boolean|undefined),
- *   downloads: (undefined|DownloadsPageVisibility),
+ *   downloads: (boolean|undefined|DownloadsPageVisibility),
  *   onStartup: (boolean|undefined),
  *   passwordsAndForms: (boolean|undefined),
  *   people: (boolean|undefined),
- *   privacy: (undefined|PrivacyPageVisibility),
+ *   privacy: (boolean|undefined|PrivacyPageVisibility),
  *   reset:(boolean|undefined),
  * }}
  */
@@ -53,7 +53,6 @@
 var PrivacyPageVisibility;
 
 cr.define('settings', function() {
-
   /**
    * Dictionary defining page visibility.
    * This is only set when in guest mode. All pages are visible when not set
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js
index abf59371..b621c11c 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js
@@ -18,11 +18,16 @@
   /** @override */
   ready: function() {
     this.focusConfig_ = new Map();
-    this.focusConfig_.set(
-        settings.Route.AUTOFILL.path, '#autofillManagerButton .subpage-arrow');
-    this.focusConfig_.set(
-        settings.Route.MANAGE_PASSWORDS.path,
-        '#passwordManagerButton .subpage-arrow');
+    if (settings.routes.AUTOFILL) {
+      this.focusConfig_.set(
+          settings.routes.AUTOFILL.path,
+          '#autofillManagerButton .subpage-arrow');
+    }
+    if (settings.routes.MANAGE_PASSWORDS) {
+      this.focusConfig_.set(
+          settings.routes.MANAGE_PASSWORDS.path,
+          '#passwordManagerButton .subpage-arrow');
+    }
   },
 
   /**
@@ -31,7 +36,7 @@
    * @private
    */
   onAutofillTap_: function(event) {
-    settings.navigateTo(settings.Route.AUTOFILL);
+    settings.navigateTo(settings.routes.AUTOFILL);
   },
 
   /**
@@ -40,6 +45,6 @@
    * @private
    */
   onPasswordsTap_: function(event) {
-    settings.navigateTo(settings.Route.MANAGE_PASSWORDS);
+    settings.navigateTo(settings.routes.MANAGE_PASSWORDS);
   },
 });
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
index f47dbec..5d02de6 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
@@ -186,7 +186,7 @@
     /** @override */
     subpageRoute: {
       type: Object,
-      value: settings.Route.MANAGE_PASSWORDS,
+      value: settings.routes.MANAGE_PASSWORDS,
     },
 
     /**
diff --git a/chrome/browser/resources/settings/people_page/change_picture.html b/chrome/browser/resources/settings/people_page/change_picture.html
index fa65ecf..e182434 100644
--- a/chrome/browser/resources/settings/people_page/change_picture.html
+++ b/chrome/browser/resources/settings/people_page/change_picture.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_camera.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_picture_preview.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_picture_types.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/util.html">
@@ -65,32 +66,11 @@
         color: var(--paper-grey-600);
       }
 
-      #previewPane {
+      cr-picture-preview {
         -webkit-margin-end: 10px;
         flex-shrink: 0;
         width: 228px;
       }
-
-      #previewPane img {
-        display: block;
-        height: 228px;
-        width: 228px;
-      }
-
-      #discardControlBar {
-        background-color: var(--paper-grey-800);
-        border-bottom-left-radius: 2px;
-        border-bottom-right-radius: 2px;
-        padding: 8px;
-      }
-
-      #discardOldImage {
-        --iron-icon-fill-color: white;
-        background-color: var(--paper-red-500);
-        border-radius: 50%;
-        display: block;
-        margin: 0 auto 0 auto;
-      }
     </style>
     <div id="container" class="settings-box" tabindex="0">
       <iron-a11y-keys keys="up down left right space enter"
@@ -115,7 +95,7 @@
               title="$i18n{oldPhoto}">
           <template is="dom-repeat" items="[[defaultImages_]]">
             <img data-type$="[[selectionTypesEnum_.DEFAULT]]" role="radio"
-                data-default-image-index$="[[index]]" src="[[item.url]]"
+                data-index$="[[index]]" src="[[item.url]]"
                 title="[[item.title]]">
           </template>
         </iron-selector>
@@ -130,24 +110,15 @@
           </div>
         </template>
       </div>
-      <div id="previewPane">
-        <img alt="$i18n{previewAltText}" src="[[selectedItem_.src]]"
-            hidden="[[isPreviewImageHidden_(selectedItem_)]]">
-        <div id="discardControlBar"
-            hidden="[[isDiscardHidden_(selectedItem_)]]">
-          <button is="paper-icon-button-light" id="discardOldImage"
-              class="icon-delete" title="$i18n{discardPhoto}"
-              on-tap="onTapDiscardOldImage_">
-          </button>
-        </div>
-        <cr-camera id="camera"
-            camera-active="[[isCameraActive_(cameraPresent_, selectedItem_)]]"
-            on-photo-taken="onPhotoTaken_"
-            on-photo-flipped="onPhotoFlipped_"
-            flip-photo-label="$i18n{flipPhoto}"
-            take-photo-label="$i18n{takePhoto}">
-        </cr-camera>
-      </div>
+      <cr-picture-preview id="picturePreview" 
+          camera-present="[[cameraPresent_]]",
+          image-src="[[getImageSrc_(selectedItem_)]]"
+          image-type="[[getImageType_(selectedItem_)]]"
+          discard-image-label="$i18n{discardPhoto}"
+          flip-photo-label="$i18n{flipPhoto}"
+          preview-alt-text="$i18n{previewAltText}"
+          take-photo-label="$i18n{takePhoto}">
+      </cr-picture-preview>
     </div>
   </template>
   <script src="change_picture.js"></script>
diff --git a/chrome/browser/resources/settings/people_page/change_picture.js b/chrome/browser/resources/settings/people_page/change_picture.js
index 8b258d7..ee3e3d27 100644
--- a/chrome/browser/resources/settings/people_page/change_picture.js
+++ b/chrome/browser/resources/settings/people_page/change_picture.js
@@ -3,30 +3,6 @@
 // found in the LICENSE file.
 
 /**
- * Contains the possible types of Change Picture selections.
- * @enum {string}
- */
-var ChangePictureSelectionTypes = {
-  CAMERA: 'camera',
-  FILE: 'file',
-  PROFILE: 'profile',
-  OLD: 'old',
-  DEFAULT: 'default',
-};
-
-/**
- * An image element.
- * @typedef {{
- *   dataset: {
- *     type: !ChangePictureSelectionTypes,
- *     defaultImageIndex: ?number,
- *   },
- *   src: string,
- * }}
- */
-var ChangePictureImageElement;
-
-/**
  * @fileoverview
  * 'settings-change-picture' is the settings subpage containing controls to
  * edit a ChromeOS user's picture.
@@ -54,7 +30,7 @@
      * The currently selected item. This property is bound to the iron-selector
      * and never directly assigned. This may be undefined momentarily as
      * the selection changes due to iron-selector implementation details.
-     * @private {?ChangePictureImageElement}
+     * @private {?CrPicture.ImageElement}
      */
     selectedItem_: Object,
 
@@ -93,18 +69,24 @@
     /** @private */
     selectionTypesEnum_: {
       type: Object,
-      value: ChangePictureSelectionTypes,
+      value: CrPicture.SelectionTypes,
       readOnly: true,
     },
   },
 
+  listeners: {
+    'discard-image': 'onDiscardImage_',
+    'photo-flipped': 'onPhotoFlipped_',
+    'photo-taken': 'onPhotoTaken_',
+  },
+
   /** @private {?settings.ChangePictureBrowserProxy} */
   browserProxy_: null,
 
   /**
    * The fallback image to be selected when the user discards the Old image.
    * This may be null if the user started with the Old image.
-   * @private {?ChangePictureImageElement}
+   * @private {?CrPicture.ImageElement}
    */
   fallbackImage_: null,
 
@@ -137,7 +119,7 @@
 
   /** @protected */
   currentRouteChanged: function(newRoute) {
-    if (newRoute == settings.Route.CHANGE_PICTURE) {
+    if (newRoute == settings.routes.CHANGE_PICTURE) {
       this.browserProxy_.initialize();
 
       // This in needed because we manually clear the selectedItem_ property
@@ -170,7 +152,7 @@
    */
   receiveSelectedImage_: function(imageUrl) {
     var index = this.$.selector.items.findIndex(function(image) {
-      return image.dataset.type == ChangePictureSelectionTypes.DEFAULT &&
+      return image.dataset.type == CrPicture.SelectionTypes.DEFAULT &&
           image.src == imageUrl;
     });
     assert(index != -1, 'Default image not found: ' + imageUrl);
@@ -179,7 +161,7 @@
 
     // If user is currently taking a photo, do not steal the focus.
     if (!this.selectedItem_ ||
-        this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) {
+        this.selectedItem_.dataset.type != CrPicture.SelectionTypes.CAMERA) {
       this.$.selector.select(index);
     }
   },
@@ -214,7 +196,7 @@
 
     // If user is currently taking a photo, do not steal the focus.
     if (!this.selectedItem_ ||
-        this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) {
+        this.selectedItem_.dataset.type != CrPicture.SelectionTypes.CAMERA) {
       this.$.selector.select(this.$.selector.indexOf(this.$.profileImage));
     }
   },
@@ -230,24 +212,24 @@
 
   /**
    * Selects an image element.
-   * @param {!ChangePictureImageElement} image
+   * @param {!CrPicture.ImageElement} image
    * @private
    */
   selectImage_: function(image) {
     switch (image.dataset.type) {
-      case ChangePictureSelectionTypes.CAMERA:
+      case CrPicture.SelectionTypes.CAMERA:
         // Nothing needs to be done.
         break;
-      case ChangePictureSelectionTypes.FILE:
+      case CrPicture.SelectionTypes.FILE:
         this.browserProxy_.chooseFile();
         break;
-      case ChangePictureSelectionTypes.PROFILE:
+      case CrPicture.SelectionTypes.PROFILE:
         this.browserProxy_.selectProfileImage();
         break;
-      case ChangePictureSelectionTypes.OLD:
+      case CrPicture.SelectionTypes.OLD:
         this.browserProxy_.selectOldImage();
         break;
-      case ChangePictureSelectionTypes.DEFAULT:
+      case CrPicture.SelectionTypes.DEFAULT:
         this.browserProxy_.selectDefaultImage(image.src);
         break;
       default:
@@ -284,7 +266,7 @@
           selector.selectPrevious();
         } while (this.selectedItem_.hidden);
 
-        if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE)
+        if (this.selectedItem_.dataset.type != CrPicture.SelectionTypes.FILE)
           this.selectImage_(this.selectedItem_);
 
         this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
@@ -299,7 +281,7 @@
           selector.selectNext();
         } while (this.selectedItem_.hidden);
 
-        if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE)
+        if (this.selectedItem_.dataset.type != CrPicture.SelectionTypes.FILE)
           this.selectImage_(this.selectedItem_);
 
         this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
@@ -309,17 +291,14 @@
       case 'enter':
       case 'space':
         if (this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.CAMERA) {
-          var /** CrCameraElement */ camera = this.$.camera;
-          camera.takePhoto();
+            CrPicture.SelectionTypes.CAMERA) {
+          /** CrPicturePreviewElement */ (this.$.picturePreview).takePhoto();
         } else if (
-            this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.FILE) {
+            this.selectedItem_.dataset.type == CrPicture.SelectionTypes.FILE) {
           this.browserProxy_.chooseFile();
         } else if (
-            this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.OLD) {
-          this.onTapDiscardOldImage_();
+            this.selectedItem_.dataset.type == CrPicture.SelectionTypes.OLD) {
+          this.onDiscardImage_();
         }
         break;
     }
@@ -359,14 +338,14 @@
   },
 
   /**
-   * Discard currently selected Old image. Selects the first default icon.
+   * Discard currently selected image. Selects the first default icon.
    * Returns to the camera stream if the user had just taken a picture.
    * @private
    */
-  onTapDiscardOldImage_: function() {
+  onDiscardImage_: function() {
     this.oldImageUrl_ = '';
 
-    if (this.lastSelectedImageType_ == ChangePictureSelectionTypes.CAMERA)
+    if (this.lastSelectedImageType_ == CrPicture.SelectionTypes.CAMERA)
       this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage));
 
     if (this.fallbackImage_ != null) {
@@ -383,63 +362,36 @@
   },
 
   /**
-   * @param {string} oldImageUrl
-   * @return {boolean} True if there is no Old image and the Old image icon
-   *     should be hidden.
+   * @param {CrPicture.ImageElement} selectedItem
+   * @return {string}
    * @private
    */
-  isOldImageHidden_: function(oldImageUrl) {
-    return oldImageUrl.length == 0;
+  getImageSrc_: function(selectedItem) {
+    return (selectedItem && selectedItem.src) || '';
   },
 
   /**
-   * @param {ChangePictureImageElement} selectedItem
-   * @return {boolean} True if the preview image should be hidden.
+   * @param {CrPicture.ImageElement} selectedItem
+   * @return {string}
    * @private
    */
-  isPreviewImageHidden_: function(selectedItem) {
-    if (!selectedItem)
-      return true;
-
-    var type = selectedItem.dataset.type;
-    return type != ChangePictureSelectionTypes.DEFAULT &&
-        type != ChangePictureSelectionTypes.PROFILE &&
-        type != ChangePictureSelectionTypes.OLD;
+  getImageType_: function(selectedItem) {
+    return (selectedItem && selectedItem.dataset.type) ||
+        CrPicture.SelectionTypes.NONE;
   },
 
   /**
-   * @param {boolean} cameraPresent
-   * @param {ChangePictureImageElement} selectedItem
-   * @return {boolean} True if the camera is selected in the image grid.
-   * @private
-   */
-  isCameraActive_: function(cameraPresent, selectedItem) {
-    return cameraPresent && !!selectedItem &&
-        selectedItem.dataset.type == ChangePictureSelectionTypes.CAMERA;
-  },
-
-  /**
-   * @param {ChangePictureImageElement} selectedItem
-   * @return {boolean} True if the discard controls should be hidden.
-   * @private
-   */
-  isDiscardHidden_: function(selectedItem) {
-    return !selectedItem ||
-        selectedItem.dataset.type != ChangePictureSelectionTypes.OLD;
-  },
-
-  /**
-   * @param {ChangePictureImageElement} selectedItem
+   * @param {CrPicture.ImageElement} selectedItem
    * @return {boolean} True if the author credit text is shown.
    * @private
    */
   isAuthorCreditShown_: function(selectedItem) {
     return !!selectedItem &&
-        selectedItem.dataset.type == ChangePictureSelectionTypes.DEFAULT;
+        selectedItem.dataset.type == CrPicture.SelectionTypes.DEFAULT;
   },
 
   /**
-   * @param {!ChangePictureImageElement} selectedItem
+   * @param {!CrPicture.ImageElement} selectedItem
    * @param {!Array<!settings.DefaultImage>} defaultImages
    * @return {string} The author name for the selected default image. An empty
    *     string is returned if there is no valid author name.
@@ -450,13 +402,13 @@
       return '';
 
     assert(
-        selectedItem.dataset.defaultImageIndex !== null &&
-        selectedItem.dataset.defaultImageIndex < defaultImages.length);
-    return defaultImages[selectedItem.dataset.defaultImageIndex].author;
+        selectedItem.dataset.index !== null &&
+        selectedItem.dataset.index < defaultImages.length);
+    return defaultImages[selectedItem.dataset.index].author;
   },
 
   /**
-   * @param {!ChangePictureImageElement} selectedItem
+   * @param {!CrPicture.ImageElement} selectedItem
    * @param {!Array<!settings.DefaultImage>} defaultImages
    * @return {string} The author website for the selected default image. An
    *     empty string is returned if there is no valid author name.
@@ -467,8 +419,8 @@
       return '';
 
     assert(
-        selectedItem.dataset.defaultImageIndex !== null &&
-        selectedItem.dataset.defaultImageIndex < defaultImages.length);
-    return defaultImages[selectedItem.dataset.defaultImageIndex].website;
+        selectedItem.dataset.index !== null &&
+        selectedItem.dataset.index < defaultImages.length);
+    return defaultImages[selectedItem.dataset.index].website;
   },
 });
diff --git a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
index b76d019..73f3e2aa 100644
--- a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -6,7 +6,8 @@
     {
       'target_name': 'change_picture',
       'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_camera',
+        '<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_picture_preview',
+        '<(DEPTH)/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp:cr_picture_types',
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-selector/compiled_resources2.gyp:iron-selector-extracted',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.js b/chrome/browser/resources/settings/people_page/fingerprint_list.js
index 2fbc3d8..d6c142e 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_list.js
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.js
@@ -62,10 +62,10 @@
    * @protected
    */
   currentRouteChanged: function(newRoute, oldRoute) {
-    if (newRoute != settings.Route.FINGERPRINT) {
+    if (newRoute != settings.routes.FINGERPRINT) {
       if (this.browserProxy_)
         this.browserProxy_.endCurrentAuthentication();
-    } else if (oldRoute == settings.Route.LOCK_SCREEN) {
+    } else if (oldRoute == settings.routes.LOCK_SCREEN) {
       // Start fingerprint authentication when going from LOCK_SCREEN to
       // FINGERPRINT page.
       this.browserProxy_.startAuthentication();
@@ -166,7 +166,7 @@
    */
   onScreenLocked_: function(screenIsLocked) {
     if (!screenIsLocked &&
-        settings.getCurrentRoute() == settings.Route.FINGERPRINT) {
+        settings.getCurrentRoute() == settings.routes.FINGERPRINT) {
       this.onSetupFingerprintDialogClose_();
     }
   },
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index f5b62a7..4e14d4b 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -166,7 +166,7 @@
    * @protected
    */
   currentRouteChanged: function(newRoute, oldRoute) {
-    if (newRoute == settings.Route.LOCK_SCREEN &&
+    if (newRoute == settings.routes.LOCK_SCREEN &&
         this.fingerprintUnlockEnabled_ && this.fingerprintBrowserProxy_) {
       this.fingerprintBrowserProxy_.getNumFingerprints().then(
           function(numFingerprints) {
@@ -177,8 +177,8 @@
     if (this.shouldAskForPassword_(newRoute)) {
       this.openPasswordPromptDialog_();
     } else if (
-        newRoute != settings.Route.FINGERPRINT &&
-        oldRoute != settings.Route.FINGERPRINT) {
+        newRoute != settings.routes.FINGERPRINT &&
+        oldRoute != settings.routes.FINGERPRINT) {
       // If the user navigated away from the lock screen settings page they will
       // have to re-enter their password. An exception is if they are navigating
       // to or from the fingerprint subpage.
@@ -272,7 +272,7 @@
 
   /** @private */
   onEditFingerprints_: function() {
-    settings.navigateTo(settings.Route.FINGERPRINT);
+    settings.navigateTo(settings.routes.FINGERPRINT);
   },
 
   /**
@@ -281,7 +281,7 @@
    * @private
    */
   shouldAskForPassword_: function(route) {
-    return route == settings.Route.LOCK_SCREEN && !this.setModes_;
+    return route == settings.routes.LOCK_SCREEN && !this.setModes_;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.js b/chrome/browser/resources/settings/people_page/manage_profile.js
index 50e6a87e..91e46dae 100644
--- a/chrome/browser/resources/settings/people_page/manage_profile.js
+++ b/chrome/browser/resources/settings/people_page/manage_profile.js
@@ -77,7 +77,7 @@
 
   /** @protected */
   currentRouteChanged: function() {
-    if (settings.getCurrentRoute() == settings.Route.MANAGE_PROFILE) {
+    if (settings.getCurrentRoute() == settings.routes.MANAGE_PROFILE) {
       this.$.name.value = this.profileName;
 
       if (loadTimeData.getBoolean('profileShortcutsEnabled')) {
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index 88890ad32..35b743b 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -93,22 +93,31 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(settings.Route.SYNC.path, '#sync-status .subpage-arrow');
+        if (settings.routes.SYNC)
+          map.set(settings.routes.SYNC.path, '#sync-status .subpage-arrow');
         // <if expr="not chromeos">
-        map.set(
-            settings.Route.MANAGE_PROFILE.path,
-            '#picture-subpage-trigger .subpage-arrow');
+        if (settings.routes.MANAGE_PROFILE) {
+          map.set(
+              settings.routes.MANAGE_PROFILE.path,
+              '#picture-subpage-trigger .subpage-arrow');
+        }
         // </if>
         // <if expr="chromeos">
-        map.set(
-            settings.Route.CHANGE_PICTURE.path,
-            '#picture-subpage-trigger .subpage-arrow');
-        map.set(
-            settings.Route.LOCK_SCREEN.path,
-            '#lock-screen-subpage-trigger .subpage-arrow');
-        map.set(
-            settings.Route.ACCOUNTS.path,
-            '#manage-other-people-subpage-trigger .subpage-arrow');
+        if (settings.routes.CHANGE_PICTURE) {
+          map.set(
+              settings.routes.CHANGE_PICTURE.path,
+              '#picture-subpage-trigger .subpage-arrow');
+        }
+        if (settings.routes.LOCK_SCREEN) {
+          map.set(
+              settings.routes.LOCK_SCREEN.path,
+              '#lock-screen-subpage-trigger .subpage-arrow');
+        }
+        if (settings.routes.ACCOUNTS) {
+          map.set(
+              settings.routes.ACCOUNTS.path,
+              '#manage-other-people-subpage-trigger .subpage-arrow');
+        }
         // </if>
         return map;
       },
@@ -144,9 +153,9 @@
   /** @protected */
   currentRouteChanged: function() {
     this.showImportDataDialog_ =
-        settings.getCurrentRoute() == settings.Route.IMPORT_DATA;
+        settings.getCurrentRoute() == settings.routes.IMPORT_DATA;
 
-    if (settings.getCurrentRoute() == settings.Route.SIGN_OUT) {
+    if (settings.getCurrentRoute() == settings.routes.SIGN_OUT) {
       // If the sync status has not been fetched yet, optimistically display
       // the disconnect dialog. There is another check when the sync status is
       // fetched. The dialog will be closed then the user is not signed in.
@@ -234,17 +243,17 @@
   /** @private */
   onPictureTap_: function() {
     // <if expr="chromeos">
-    settings.navigateTo(settings.Route.CHANGE_PICTURE);
+    settings.navigateTo(settings.routes.CHANGE_PICTURE);
     // </if>
     // <if expr="not chromeos">
-    settings.navigateTo(settings.Route.MANAGE_PROFILE);
+    settings.navigateTo(settings.routes.MANAGE_PROFILE);
     // </if>
   },
 
   // <if expr="not chromeos">
   /** @private */
   onProfileNameTap_: function() {
-    settings.navigateTo(settings.Route.MANAGE_PROFILE);
+    settings.navigateTo(settings.routes.MANAGE_PROFILE);
   },
   // </if>
 
@@ -258,14 +267,14 @@
     this.showDisconnectDialog_ = false;
     cr.ui.focusWithoutInk(assert(this.$$('#disconnectButton')));
 
-    if (settings.getCurrentRoute() == settings.Route.SIGN_OUT)
+    if (settings.getCurrentRoute() == settings.routes.SIGN_OUT)
       settings.navigateToPreviousRoute();
     this.fire('signout-dialog-closed');
   },
 
   /** @private */
   onDisconnectTap_: function() {
-    settings.navigateTo(settings.Route.SIGN_OUT);
+    settings.navigateTo(settings.routes.SIGN_OUT);
   },
 
   /** @private */
@@ -307,7 +316,7 @@
         // </if>
         // <if expr="not chromeos">
         if (this.syncStatus.domain)
-          settings.navigateTo(settings.Route.SIGN_OUT);
+          settings.navigateTo(settings.routes.SIGN_OUT);
         else {
           // Silently sign the user out without deleting their profile and
           // prompt them to sign back in.
@@ -317,13 +326,13 @@
         // </if>
         break;
       case settings.StatusAction.UPGRADE_CLIENT:
-        settings.navigateTo(settings.Route.ABOUT);
+        settings.navigateTo(settings.routes.ABOUT);
         break;
       case settings.StatusAction.ENTER_PASSPHRASE:
       case settings.StatusAction.CONFIRM_SYNC_SETTINGS:
       case settings.StatusAction.NO_ACTION:
       default:
-        settings.navigateTo(settings.Route.SYNC);
+        settings.navigateTo(settings.routes.SYNC);
     }
   },
 
@@ -337,7 +346,7 @@
     // dialog, so prevent the end of the tap event to focus what is underneath
     // it, which takes focus from the dialog.
     e.preventDefault();
-    settings.navigateTo(settings.Route.LOCK_SCREEN);
+    settings.navigateTo(settings.routes.LOCK_SCREEN);
   },
   // </if>
 
@@ -347,7 +356,7 @@
     this.syncBrowserProxy_.manageOtherPeople();
     // </if>
     // <if expr="chromeos">
-    settings.navigateTo(settings.Route.ACCOUNTS);
+    settings.navigateTo(settings.routes.ACCOUNTS);
     // </if>
   },
 
@@ -364,7 +373,7 @@
 
   /** @private */
   onImportDataTap_: function() {
-    settings.navigateTo(settings.Route.IMPORT_DATA);
+    settings.navigateTo(settings.routes.IMPORT_DATA);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/people_page/sync_page.js b/chrome/browser/resources/settings/people_page/sync_page.js
index 779ff49..18102cf 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chrome/browser/resources/settings/people_page/sync_page.js
@@ -140,19 +140,19 @@
     this.addWebUIListener(
         'sync-prefs-changed', this.handleSyncPrefsChanged_.bind(this));
 
-    if (settings.getCurrentRoute() == settings.Route.SYNC)
+    if (settings.getCurrentRoute() == settings.routes.SYNC)
       this.onNavigateToPage_();
   },
 
   /** @override */
   detached: function() {
-    if (settings.getCurrentRoute() == settings.Route.SYNC)
+    if (settings.getCurrentRoute() == settings.routes.SYNC)
       this.onNavigateAwayFromPage_();
   },
 
   /** @protected */
   currentRouteChanged: function() {
-    if (settings.getCurrentRoute() == settings.Route.SYNC)
+    if (settings.getCurrentRoute() == settings.routes.SYNC)
       this.onNavigateToPage_();
     else
       this.onNavigateAwayFromPage_();
@@ -169,7 +169,7 @@
 
   /** @private */
   onNavigateToPage_: function() {
-    assert(settings.getCurrentRoute() == settings.Route.SYNC);
+    assert(settings.getCurrentRoute() == settings.routes.SYNC);
 
     if (this.unloadCallback_)
       return;
@@ -350,8 +350,8 @@
         this.pageStatus_ = pageStatus;
         return;
       case settings.PageStatus.DONE:
-        if (settings.getCurrentRoute() == settings.Route.SYNC)
-          settings.navigateTo(settings.Route.PEOPLE);
+        if (settings.getCurrentRoute() == settings.routes.SYNC)
+          settings.navigateTo(settings.routes.PEOPLE);
         return;
       case settings.PageStatus.PASSPHRASE_FAILED:
         if (this.pageStatus_ == this.pages_.CONFIGURE && this.syncPrefs &&
diff --git a/chrome/browser/resources/settings/people_page/user_list.js b/chrome/browser/resources/settings/people_page/user_list.js
index 8ec5da3..f1cbc79 100644
--- a/chrome/browser/resources/settings/people_page/user_list.js
+++ b/chrome/browser/resources/settings/people_page/user_list.js
@@ -60,7 +60,7 @@
 
   /** @protected */
   currentRouteChanged: function() {
-    if (settings.getCurrentRoute() == settings.Route.ACCOUNTS) {
+    if (settings.getCurrentRoute() == settings.routes.ACCOUNTS) {
       chrome.usersPrivate.getWhitelistedUsers(function(users) {
         this.setUsers_(users);
       }.bind(this));
diff --git a/chrome/browser/resources/settings/printing_page/printing_page.js b/chrome/browser/resources/settings/printing_page/printing_page.js
index 2a783f10..6ca0162 100644
--- a/chrome/browser/resources/settings/printing_page/printing_page.js
+++ b/chrome/browser/resources/settings/printing_page/printing_page.js
@@ -40,12 +40,17 @@
       type: Object,
       value: function() {
         var map = new Map();
-        map.set(
-            settings.Route.CLOUD_PRINTERS.path,
-            '#cloudPrinters .subpage-arrow');
+        if (settings.routes.CLOUD_PRINTERS) {
+          map.set(
+              settings.routes.CLOUD_PRINTERS.path,
+              '#cloudPrinters .subpage-arrow');
+        }
         // <if expr="chromeos">
-        map.set(
-            settings.Route.CUPS_PRINTERS.path, '#cupsPrinters .subpage-arrow');
+        if (settings.routes.CUPS_PRINTERS) {
+          map.set(
+              settings.routes.CUPS_PRINTERS.path,
+              '#cupsPrinters .subpage-arrow');
+        }
         // </if>
         return map;
       },
@@ -59,18 +64,18 @@
   // <if expr="chromeos">
   /** @private */
   onTapCupsPrinters_: function() {
-    settings.navigateTo(settings.Route.CUPS_PRINTERS);
+    settings.navigateTo(settings.routes.CUPS_PRINTERS);
   },
 
   /** @private */
   onShowCupsPrinterDetailsPage_: function(event) {
-    settings.navigateTo(settings.Route.CUPS_PRINTER_DETAIL);
+    settings.navigateTo(settings.routes.CUPS_PRINTER_DETAIL);
     this.$.arraySelector.select(event.detail);
   },
   // </if>
 
   /** @private */
   onTapCloudPrinters_: function() {
-    settings.navigateTo(settings.Route.CLOUD_PRINTERS);
+    settings.navigateTo(settings.routes.CLOUD_PRINTERS);
   },
 });
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 4c6061ec..1aff584 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -105,13 +105,17 @@
       value: function() {
         var map = new Map();
         // <if expr="use_nss_certs">
-        map.set(
-            settings.Route.CERTIFICATES.path,
-            '#manageCertificates .subpage-arrow');
+        if (settings.routes.CERTIFICATES) {
+          map.set(
+              settings.routes.CERTIFICATES.path,
+              '#manageCertificates .subpage-arrow');
+        }
         // </if>
-        map.set(
-            settings.Route.SITE_SETTINGS.path,
-            '#site-settings-subpage-trigger .subpage-arrow');
+        if (settings.routes.SITE_SETTINGS) {
+          map.set(
+              settings.routes.SITE_SETTINGS.path,
+              '#site-settings-subpage-trigger .subpage-arrow');
+        }
         return map;
       },
     },
@@ -141,7 +145,7 @@
   /** @protected */
   currentRouteChanged: function() {
     this.showClearBrowsingDataDialog_ =
-        settings.getCurrentRoute() == settings.Route.CLEAR_BROWSER_DATA;
+        settings.getCurrentRoute() == settings.routes.CLEAR_BROWSER_DATA;
   },
 
   /**
@@ -214,7 +218,7 @@
   /** @private */
   onManageCertificatesTap_: function() {
     // <if expr="use_nss_certs">
-    settings.navigateTo(settings.Route.CERTIFICATES);
+    settings.navigateTo(settings.routes.CERTIFICATES);
     // </if>
     // <if expr="is_win or is_macosx">
     this.browserProxy_.showManageSSLCertificates();
@@ -234,12 +238,12 @@
 
   /** @private */
   onSiteSettingsTap_: function() {
-    settings.navigateTo(settings.Route.SITE_SETTINGS);
+    settings.navigateTo(settings.routes.SITE_SETTINGS);
   },
 
   /** @private */
   onClearBrowsingDataTap_: function() {
-    settings.navigateTo(settings.Route.CLEAR_BROWSER_DATA);
+    settings.navigateTo(settings.routes.CLEAR_BROWSER_DATA);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.js b/chrome/browser/resources/settings/reset_page/reset_page.js
index 64a36e1..2c4d88e 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.js
+++ b/chrome/browser/resources/settings/reset_page/reset_page.js
@@ -46,14 +46,14 @@
    */
   currentRouteChanged: function(route) {
     this.showResetProfileDialog_ =
-        route == settings.Route.TRIGGERED_RESET_DIALOG ||
-        route == settings.Route.RESET_DIALOG;
+        route == settings.routes.TRIGGERED_RESET_DIALOG ||
+        route == settings.routes.RESET_DIALOG;
   },
 
   /** @private */
   onShowResetProfileDialog_: function() {
     settings.navigateTo(
-        settings.Route.RESET_DIALOG, new URLSearchParams('origin=userclick'));
+        settings.routes.RESET_DIALOG, new URLSearchParams('origin=userclick'));
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_banner.js b/chrome/browser/resources/settings/reset_page/reset_profile_banner.js
index 965efd65..9b95c0f1 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_banner.js
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_banner.js
@@ -33,6 +33,6 @@
   /** @private */
   onResetTap_: function() {
     this.$.dialog.close();
-    settings.navigateTo(settings.Route.RESET_DIALOG);
+    settings.navigateTo(settings.routes.RESET_DIALOG);
   },
 });
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
index 0e63dd8b..ccbe17a0 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
@@ -94,7 +94,7 @@
   /** @override */
   attached: function() {
     this.isTriggered_ =
-        settings.getCurrentRoute() == settings.Route.TRIGGERED_RESET_DIALOG;
+        settings.getCurrentRoute() == settings.routes.TRIGGERED_RESET_DIALOG;
     if (this.isTriggered_) {
       this.browserProxy_.getTriggeredResetToolName().then(function(name) {
         this.resetRequestOrigin_ = 'triggeredreset';
diff --git a/chrome/browser/resources/settings/route.html b/chrome/browser/resources/settings/route.html
index 1300e857..4156107 100644
--- a/chrome/browser/resources/settings/route.html
+++ b/chrome/browser/resources/settings/route.html
@@ -1,4 +1,5 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="i18n_setup.html">
+<link rel="import" href="page_visibility.html">
 
 <script src="route.js"></script>
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index ed960c6..02add787 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -2,36 +2,124 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * Specifies all possible routes in settings.
+ *
+ * @typedef {{
+ *   ABOUT: (undefined|!settings.Route),
+ *   ABOUT_ABOUT: (undefined|!settings.Route),
+ *   ACCESSIBILITY: (undefined|!settings.Route),
+ *   ACCOUNTS: (undefined|!settings.Route),
+ *   ADVANCED: (undefined|!settings.Route),
+ *   ANDROID_APPS: (undefined|!settings.Route),
+ *   ANDROID_APPS_DETAILS: (undefined|!settings.Route),
+ *   APPEARANCE: (undefined|!settings.Route),
+ *   AUTOFILL: (undefined|!settings.Route),
+ *   BASIC: (undefined|!settings.Route),
+ *   BLUETOOTH: (undefined|!settings.Route),
+ *   BLUETOOTH_DEVICES: (undefined|!settings.Route),
+ *   CERTIFICATES: (undefined|!settings.Route),
+ *   CHANGE_PICTURE: (undefined|!settings.Route),
+ *   CLEAR_BROWSER_DATA: (undefined|!settings.Route),
+ *   CLOUD_PRINTERS: (undefined|!settings.Route),
+ *   CUPS_PRINTER_DETAIL: (undefined|!settings.Route),
+ *   CUPS_PRINTERS: (undefined|!settings.Route),
+ *   DATETIME: (undefined|!settings.Route),
+ *   DEFAULT_BROWSER: (undefined|!settings.Route),
+ *   DETAILED_BUILD_INFO: (undefined|!settings.Route),
+ *   DEVICE: (undefined|!settings.Route),
+ *   DISPLAY: (undefined|!settings.Route),
+ *   DOWNLOADS: (undefined|!settings.Route),
+ *   EDIT_DICTIONARY: (undefined|!settings.Route),
+ *   FINGERPRINT: (undefined|!settings.Route),
+ *   FONTS: (undefined|!settings.Route),
+ *   IMPORT_DATA: (undefined|!settings.Route),
+ *   INPUT_METHODS: (undefined|!settings.Route),
+ *   INTERNET: (undefined|!settings.Route),
+ *   INTERNET_NETWORKS: (undefined|!settings.Route),
+ *   KEYBOARD: (undefined|!settings.Route),
+ *   KNOWN_NETWORKS: (undefined|!settings.Route),
+ *   LANGUAGES: (undefined|!settings.Route),
+ *   LOCK_SCREEN: (undefined|!settings.Route),
+ *   MANAGE_ACCESSIBILITY: (undefined|!settings.Route),
+ *   MANAGE_PASSWORDS: (undefined|!settings.Route),
+ *   MANAGE_PROFILE: (undefined|!settings.Route),
+ *   NETWORK_CONFIG: (undefined|!settings.Route),
+ *   NETWORK_DETAIL: (undefined|!settings.Route),
+ *   ON_STARTUP: (undefined|!settings.Route),
+ *   PASSWORDS: (undefined|!settings.Route),
+ *   PEOPLE: (undefined|!settings.Route),
+ *   POINTERS: (undefined|!settings.Route),
+ *   POWER: (undefined|!settings.Route),
+ *   PRINTING: (undefined|!settings.Route),
+ *   PRIVACY: (undefined|!settings.Route),
+ *   RESET: (undefined|!settings.Route),
+ *   RESET_DIALOG: (undefined|!settings.Route),
+ *   SEARCH: (undefined|!settings.Route),
+ *   SEARCH_ENGINES: (undefined|!settings.Route),
+ *   SIGN_OUT: (undefined|!settings.Route),
+ *   SITE_SETTINGS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_ADS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_ALL: (undefined|!settings.Route),
+ *   SITE_SETTINGS_AUTOMATIC_DOWNLOADS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_BACKGROUND_SYNC: (undefined|!settings.Route),
+ *   SITE_SETTINGS_CAMERA: (undefined|!settings.Route),
+ *   SITE_SETTINGS_COOKIES: (undefined|!settings.Route),
+ *   SITE_SETTINGS_DATA_DETAILS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_FLASH: (undefined|!settings.Route),
+ *   SITE_SETTINGS_HANDLERS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_IMAGES: (undefined|!settings.Route),
+ *   SITE_SETTINGS_JAVASCRIPT: (undefined|!settings.Route),
+ *   SITE_SETTINGS_LOCATION: (undefined|!settings.Route),
+ *   SITE_SETTINGS_MICROPHONE: (undefined|!settings.Route),
+ *   SITE_SETTINGS_MIDI_DEVICES: (undefined|!settings.Route),
+ *   SITE_SETTINGS_NOTIFICATIONS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_PDF_DOCUMENTS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_POPUPS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_PROTECTED_CONTENT: (undefined|!settings.Route),
+ *   SITE_SETTINGS_SITE_DETAILS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_UNSANDBOXED_PLUGINS: (undefined|!settings.Route),
+ *   SITE_SETTINGS_USB_DEVICES: (undefined|!settings.Route),
+ *   SITE_SETTINGS_ZOOM_LEVELS: (undefined|!settings.Route),
+ *   STORAGE: (undefined|!settings.Route),
+ *   STYLUS: (undefined|!settings.Route),
+ *   SYNC: (undefined|!settings.Route),
+ *   SYSTEM: (undefined|!settings.Route),
+ *   TRIGGERED_RESET_DIALOG: (undefined|!settings.Route),
+ * }}
+ */
+var SettingsRoutes;
+
 cr.define('settings', function() {
+
   /**
    * Class for navigable routes. May only be instantiated within this file.
-   * @constructor
-   * @param {string} path
-   * @private
    */
-  var Route = function(path) {
-    this.path = path;
+  class Route {
+    /** @param {string} path */
+    constructor(path) {
+      /** @type {string} */
+      this.path = path;
 
-    /** @type {?settings.Route} */
-    this.parent = null;
+      /** @type {?settings.Route} */
+      this.parent = null;
 
-    /** @type {number} */
-    this.depth = 0;
+      /** @type {number} */
+      this.depth = 0;
 
-    /**
-     * @type {boolean} Whether this route corresponds to a navigable
-     *     dialog. Those routes don't belong to a "section".
-     */
-    this.isNavigableDialog = false;
+      /**
+       * @type {boolean} Whether this route corresponds to a navigable
+       *     dialog. Those routes don't belong to a "section".
+       */
+      this.isNavigableDialog = false;
 
-    // Below are all legacy properties to provide compatibility with the old
-    // routing system.
+      // Below are all legacy properties to provide compatibility with the old
+      // routing system.
 
-    /** @type {string} */
-    this.section = '';
-  };
+      /** @type {string} */
+      this.section = '';
+    }
 
-  Route.prototype = {
     /**
      * Returns a new Route instance that's a child of this route.
      * @param {string} path Extends this route's path if it doesn't contain a
@@ -39,7 +127,7 @@
      * @return {!settings.Route}
      * @private
      */
-    createChild: function(path) {
+    createChild(path) {
       assert(path);
 
       // |path| extends this route's path if it doesn't have a leading slash.
@@ -52,7 +140,7 @@
       route.depth = this.depth + 1;
 
       return route;
-    },
+    }
 
     /**
      * Returns a new Route instance that's a child section of this route.
@@ -62,189 +150,398 @@
      * @return {!settings.Route}
      * @private
      */
-    createSection: function(path, section) {
+    createSection(path, section) {
       var route = this.createChild(path);
       route.section = section;
       return route;
-    },
+    }
 
     /**
      * Returns true if this route matches or is an ancestor of the parameter.
      * @param {!settings.Route} route
      * @return {boolean}
      */
-    contains: function(route) {
+    contains(route) {
       for (var r = route; r != null; r = r.parent) {
         if (this == r)
           return true;
       }
       return false;
-    },
+    }
 
     /**
      * Returns true if this route is a subpage of a section.
      * @return {boolean}
      */
-    isSubpage: function() {
+    isSubpage() {
       return !!this.parent && !!this.section &&
           this.parent.section == this.section;
-    },
-  };
-
-  // Abbreviated variable for easier definitions.
-  var r = Route;
-
-  // Root pages.
-  r.BASIC = new Route('/');
-  r.ADVANCED = new Route('/advanced');
-  r.ABOUT = new Route('/help');
-
-  // Navigable dialogs. These are the only non-section children of root pages.
-  // These are disfavored. If we add anymore, we should add explicit support.
-  r.IMPORT_DATA = r.BASIC.createChild('/importData');
-  r.IMPORT_DATA.isNavigableDialog = true;
-  r.SIGN_OUT = r.BASIC.createChild('/signOut');
-  r.SIGN_OUT.isNavigableDialog = true;
-  r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData');
-  r.CLEAR_BROWSER_DATA.isNavigableDialog = true;
-  r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings');
-  r.RESET_DIALOG.isNavigableDialog = true;
-  r.TRIGGERED_RESET_DIALOG =
-      r.ADVANCED.createChild('/triggeredResetProfileSettings');
-  r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true;
-
-  // <if expr="chromeos">
-  r.INTERNET = r.BASIC.createSection('/internet', 'internet');
-  r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks');
-  r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig');
-  r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail');
-  r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks');
-  r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth');
-  r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices');
-  // </if>
-
-  r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance');
-  r.FONTS = r.APPEARANCE.createChild('/fonts');
-
-  r.DEFAULT_BROWSER =
-      r.BASIC.createSection('/defaultBrowser', 'defaultBrowser');
-
-  r.SEARCH = r.BASIC.createSection('/search', 'search');
-  r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines');
-
-  // <if expr="chromeos">
-  r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps');
-  r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details');
-  // </if>
-
-  r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup');
-  r.STARTUP_URLS = r.ON_STARTUP.createChild('/startupUrls');
-
-  r.PEOPLE = r.BASIC.createSection('/people', 'people');
-  r.SYNC = r.PEOPLE.createChild('/syncSetup');
-  // <if expr="not chromeos">
-  r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
-  // </if>
-  // <if expr="chromeos">
-  r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture');
-  r.ACCOUNTS = r.PEOPLE.createChild('/accounts');
-  r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen');
-  r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint');
-
-  r.DEVICE = r.BASIC.createSection('/device', 'device');
-  r.POINTERS = r.DEVICE.createChild('/pointer-overlay');
-  r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay');
-  r.STYLUS = r.DEVICE.createChild('/stylus');
-  r.DISPLAY = r.DEVICE.createChild('/display');
-  r.STORAGE = r.DEVICE.createChild('/storage');
-  r.POWER = r.DEVICE.createChild('/power');
-  // </if>
-
-  r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy');
-  r.CERTIFICATES = r.PRIVACY.createChild('/certificates');
-
-  r.SITE_SETTINGS = r.PRIVACY.createChild('/content');
-
-  if (loadTimeData.getBoolean('enableSiteSettings')) {
-    r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all');
-    r.SITE_SETTINGS_SITE_DETAILS =
-        r.SITE_SETTINGS_ALL.createChild('/content/siteDetails');
-  } else if (loadTimeData.getBoolean('enableSiteDetails')) {
-    // When there is no "All Sites", pressing 'back' from "Site Details" should
-    // return to "Content Settings". This should only occur when |kSiteSettings|
-    // is off and |kSiteDetails| is on.
-    r.SITE_SETTINGS_SITE_DETAILS =
-        r.SITE_SETTINGS.createChild('/content/siteDetails');
+    }
   }
 
-  r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers');
+  /**
+   * Computes and return all available routes based on settings.pageVisibility.
+   * @return {!SettingsRoutes}
+   */
+  var computeAvailableRoutes = function() {
+    var pageVisibility = settings.pageVisibility || {};
 
-  // TODO(tommycli): Find a way to refactor these repetitive category routes.
-  r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads');
-  r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS =
-      r.SITE_SETTINGS.createChild('automaticDownloads');
-  r.SITE_SETTINGS_BACKGROUND_SYNC =
-      r.SITE_SETTINGS.createChild('backgroundSync');
-  r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
-  r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies');
-  r.SITE_SETTINGS_DATA_DETAILS =
-      r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail');
-  r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
-  r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
-  r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location');
-  r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone');
-  r.SITE_SETTINGS_NOTIFICATIONS = r.SITE_SETTINGS.createChild('notifications');
-  r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash');
-  r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups');
-  r.SITE_SETTINGS_UNSANDBOXED_PLUGINS =
-      r.SITE_SETTINGS.createChild('unsandboxedPlugins');
-  r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices');
-  r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices');
-  r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels');
-  r.SITE_SETTINGS_PDF_DOCUMENTS = r.SITE_SETTINGS.createChild('pdfDocuments');
-  r.SITE_SETTINGS_PROTECTED_CONTENT =
-      r.SITE_SETTINGS.createChild('protectedContent');
+    /** @type {!SettingsRoutes} */
+    var r = {};
 
-  // <if expr="chromeos">
-  r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
-  // </if>
+    // Root pages.
+    r.BASIC = new Route('/');
+    r.ABOUT = new Route('/help');
 
-  r.PASSWORDS =
-      r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms');
-  r.AUTOFILL = r.PASSWORDS.createChild('/autofill');
-  r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords');
+    // Navigable dialogs. These are the only non-section children of root
+    // pages. These are disfavored. If we add anymore, we should add explicit
+    // support.
+    r.IMPORT_DATA = r.BASIC.createChild('/importData');
+    r.IMPORT_DATA.isNavigableDialog = true;
+    r.SIGN_OUT = r.BASIC.createChild('/signOut');
+    r.SIGN_OUT.isNavigableDialog = true;
 
-  r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages');
-  // <if expr="chromeos">
-  r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods');
-  // </if>
-  // <if expr="not is_macosx">
-  r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary');
-  // </if>
+    // <if expr="chromeos">
+    r.INTERNET = r.BASIC.createSection('/internet', 'internet');
+    r.INTERNET_NETWORKS = r.INTERNET.createChild('/networks');
+    r.NETWORK_CONFIG = r.INTERNET.createChild('/networkConfig');
+    r.NETWORK_DETAIL = r.INTERNET.createChild('/networkDetail');
+    r.KNOWN_NETWORKS = r.INTERNET.createChild('/knownNetworks');
+    r.BLUETOOTH = r.BASIC.createSection('/bluetooth', 'bluetooth');
+    r.BLUETOOTH_DEVICES = r.BLUETOOTH.createChild('/bluetoothDevices');
+    // </if>
 
-  r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads');
+    if (pageVisibility.appearance !== false) {
+      r.APPEARANCE = r.BASIC.createSection('/appearance', 'appearance');
+      r.FONTS = r.APPEARANCE.createChild('/fonts');
+    }
 
-  r.PRINTING = r.ADVANCED.createSection('/printing', 'printing');
-  r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters');
-  // <if expr="chromeos">
-  r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters');
-  r.CUPS_PRINTER_DETAIL = r.CUPS_PRINTERS.createChild('/cupsPrinterDetails');
-  // </if>
+    if (pageVisibility.defaultBrowser !== false) {
+      r.DEFAULT_BROWSER =
+          r.BASIC.createSection('/defaultBrowser', 'defaultBrowser');
+    }
 
-  r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
-  // <if expr="chromeos">
-  r.MANAGE_ACCESSIBILITY = r.ACCESSIBILITY.createChild('/manageAccessibility');
-  // </if>
+    r.SEARCH = r.BASIC.createSection('/search', 'search');
+    r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines');
 
-  r.SYSTEM = r.ADVANCED.createSection('/system', 'system');
-  r.RESET = r.ADVANCED.createSection('/reset', 'reset');
+    // <if expr="chromeos">
+    r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps');
+    r.ANDROID_APPS_DETAILS = r.ANDROID_APPS.createChild('/androidApps/details');
+    // </if>
 
-  // <if expr="chromeos">
-  // "About" is the only section in About, but we still need to create the route
-  // in order to show the subpage on Chrome OS.
-  r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about');
-  r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details');
-  // </if>
+    if (pageVisibility.onStartup !== false) {
+      r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup');
+      r.STARTUP_URLS = r.ON_STARTUP.createChild('/startupUrls');
+    }
+
+    if (pageVisibility.people !== false) {
+      r.PEOPLE = r.BASIC.createSection('/people', 'people');
+      r.SYNC = r.PEOPLE.createChild('/syncSetup');
+      // <if expr="not chromeos">
+      r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
+      // </if>
+      // <if expr="chromeos">
+      r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture');
+      r.ACCOUNTS = r.PEOPLE.createChild('/accounts');
+      r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen');
+      r.FINGERPRINT = r.LOCK_SCREEN.createChild('/lockScreen/fingerprint');
+      // </if>
+    }
+
+    // <if expr="chromeos">
+    r.DEVICE = r.BASIC.createSection('/device', 'device');
+    r.POINTERS = r.DEVICE.createChild('/pointer-overlay');
+    r.KEYBOARD = r.DEVICE.createChild('/keyboard-overlay');
+    r.STYLUS = r.DEVICE.createChild('/stylus');
+    r.DISPLAY = r.DEVICE.createChild('/display');
+    r.STORAGE = r.DEVICE.createChild('/storage');
+    r.POWER = r.DEVICE.createChild('/power');
+    // </if>
+
+    // Advacned Routes
+    if (pageVisibility.advancedSettings !== false) {
+      r.ADVANCED = new Route('/advanced');
+
+      r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData');
+      r.CLEAR_BROWSER_DATA.isNavigableDialog = true;
+
+      if (pageVisibility.privacy !== false) {
+        r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy');
+        r.CERTIFICATES = r.PRIVACY.createChild('/certificates');
+        r.SITE_SETTINGS = r.PRIVACY.createChild('/content');
+      }
+
+      if (loadTimeData.getBoolean('enableSiteSettings')) {
+        r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all');
+        r.SITE_SETTINGS_SITE_DETAILS =
+            r.SITE_SETTINGS_ALL.createChild('/content/siteDetails');
+      } else if (loadTimeData.getBoolean('enableSiteDetails')) {
+        // When there is no "All Sites", pressing 'back' from "Site Details"
+        // should return to "Content Settings". This should only occur when
+        // |kSiteSettings| is off and |kSiteDetails| is on.
+        r.SITE_SETTINGS_SITE_DETAILS =
+            r.SITE_SETTINGS.createChild('/content/siteDetails');
+      }
+
+      r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers');
+
+      // TODO(tommycli): Find a way to refactor these repetitive category
+      // routes.
+      r.SITE_SETTINGS_ADS = r.SITE_SETTINGS.createChild('ads');
+      r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS =
+          r.SITE_SETTINGS.createChild('automaticDownloads');
+      r.SITE_SETTINGS_BACKGROUND_SYNC =
+          r.SITE_SETTINGS.createChild('backgroundSync');
+      r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera');
+      r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies');
+      r.SITE_SETTINGS_DATA_DETAILS =
+          r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail');
+      r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images');
+      r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript');
+      r.SITE_SETTINGS_LOCATION = r.SITE_SETTINGS.createChild('location');
+      r.SITE_SETTINGS_MICROPHONE = r.SITE_SETTINGS.createChild('microphone');
+      r.SITE_SETTINGS_NOTIFICATIONS =
+          r.SITE_SETTINGS.createChild('notifications');
+      r.SITE_SETTINGS_FLASH = r.SITE_SETTINGS.createChild('flash');
+      r.SITE_SETTINGS_POPUPS = r.SITE_SETTINGS.createChild('popups');
+      r.SITE_SETTINGS_UNSANDBOXED_PLUGINS =
+          r.SITE_SETTINGS.createChild('unsandboxedPlugins');
+      r.SITE_SETTINGS_MIDI_DEVICES = r.SITE_SETTINGS.createChild('midiDevices');
+      r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices');
+      r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels');
+      r.SITE_SETTINGS_PDF_DOCUMENTS =
+          r.SITE_SETTINGS.createChild('pdfDocuments');
+      r.SITE_SETTINGS_PROTECTED_CONTENT =
+          r.SITE_SETTINGS.createChild('protectedContent');
+
+      // <if expr="chromeos">
+      if (pageVisibility.dateTime !== false) {
+        r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime');
+      }
+      // </if>
+
+      if (pageVisibility.passwordsAndForms !== false) {
+        r.PASSWORDS =
+            r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms');
+        r.AUTOFILL = r.PASSWORDS.createChild('/autofill');
+        r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords');
+      }
+
+      r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages');
+      // <if expr="chromeos">
+      r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods');
+      // </if>
+      // <if expr="not is_macosx">
+      r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary');
+      // </if>
+
+      if (pageVisibility.downloads !== false) {
+        r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads');
+      }
+
+      r.PRINTING = r.ADVANCED.createSection('/printing', 'printing');
+      r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters');
+      // <if expr="chromeos">
+      r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters');
+      r.CUPS_PRINTER_DETAIL =
+          r.CUPS_PRINTERS.createChild('/cupsPrinterDetails');
+      // </if>
+
+      r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
+      // <if expr="chromeos">
+      r.MANAGE_ACCESSIBILITY =
+          r.ACCESSIBILITY.createChild('/manageAccessibility');
+      // </if>
+
+      r.SYSTEM = r.ADVANCED.createSection('/system', 'system');
+
+      if (pageVisibility.reset !== false) {
+        r.RESET = r.ADVANCED.createSection('/reset', 'reset');
+        r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings');
+        r.RESET_DIALOG.isNavigableDialog = true;
+        r.TRIGGERED_RESET_DIALOG =
+            r.ADVANCED.createChild('/triggeredResetProfileSettings');
+        r.TRIGGERED_RESET_DIALOG.isNavigableDialog = true;
+      }
+    }
+
+    // <if expr="chromeos">
+    // "About" is the only section in About, but we still need to create the
+    // route in order to show the subpage on Chrome OS.
+    r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about');
+    r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details');
+    // </if>
+
+    return r;
+  };
+
+  class Router {
+    constructor() {
+      /**
+       * List of available routes. This is populated taking into account current
+       * state (like guest mode).
+       * @private {!SettingsRoutes}
+       */
+      this.routes_ = computeAvailableRoutes();
+
+      /**
+       * The current active route. This updated is only by settings.navigateTo
+       * or settings.initializeRouteFromUrl.
+       * @type {!settings.Route}
+       */
+      this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC);
+
+      /**
+       * The current query parameters. This is updated only by
+       * settings.navigateTo or settings.initializeRouteFromUrl.
+       * @private {!URLSearchParams}
+       */
+      this.currentQueryParameters_ = new URLSearchParams();
+
+      /** @private {boolean} */
+      this.wasLastRouteChangePopstate_ = false;
+
+      /** @private {boolean}*/
+      this.initializeRouteFromUrlCalled_ = false;
+    }
+
+    /** @return {settings.Route} */
+    getRoute(routeName) {
+      return this.routes_[routeName];
+    }
+
+    /** @return {!SettingsRoutes} */
+    getRoutes() {
+      return this.routes_;
+    }
+
+    /**
+     * Helper function to set the current route and notify all observers.
+     * @param {!settings.Route} route
+     * @param {!URLSearchParams} queryParameters
+     * @param {boolean} isPopstate
+     */
+    setCurrentRoute(route, queryParameters, isPopstate) {
+      var oldRoute = this.currentRoute;
+      this.currentRoute = route;
+      this.currentQueryParameters_ = queryParameters;
+      this.wasLastRouteChangePopstate_ = isPopstate;
+      routeObservers.forEach(function(observer) {
+        observer.currentRouteChanged(this.currentRoute, oldRoute);
+      }.bind(this));
+    }
+
+    /** @return {!settings.Route} */
+    getCurrentRoute() {
+      return this.currentRoute;
+    }
+
+    /** @return {!URLSearchParams} */
+    getQueryParameters() {
+      return new URLSearchParams(
+          this.currentQueryParameters_);  // Defensive copy.
+    }
+
+    /** @return {boolean} */
+    lastRouteChangeWasPopstate() {
+      return this.wasLastRouteChangePopstate_;
+    }
+
+    /**
+     * @param {string} path
+     * @return {?settings.Route} The matching canonical route, or null if none
+     *     matches.
+     */
+    getRouteForPath(path) {
+      // Allow trailing slash in paths.
+      var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2');
+
+      // TODO(tommycli): Use Object.values once Closure compilation supports it.
+      var matchingKey = Object.keys(this.routes_).find(function(key) {
+        return this.routes_[key].path == canonicalPath;
+      }.bind(this));
+
+      return !!matchingKey ? this.routes_[matchingKey] : null;
+    }
+
+    /**
+     * Navigates to a canonical route and pushes a new history entry.
+     * @param {!settings.Route} route
+     * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same
+     *     URL parameters in a different order will still push to history.
+     * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL
+     *     parameter during navigation. Defaults to false.
+     */
+    navigateTo(route, opt_dynamicParameters, opt_removeSearch) {
+      // The ADVANCED route only serves as a parent of subpages, and should not
+      // be possible to navigate to it directly.
+      if (route == this.routes_.ADVANCED)
+        route = /** @type {!settings.Route} */ (this.routes_.BASIC);
+
+      var params = opt_dynamicParameters || new URLSearchParams();
+      var removeSearch = !!opt_removeSearch;
+
+      var oldSearchParam = this.getQueryParameters().get('search') || '';
+      var newSearchParam = params.get('search') || '';
+
+      if (!removeSearch && oldSearchParam && !newSearchParam)
+        params.append('search', oldSearchParam);
+
+      var url = route.path;
+      var queryString = params.toString();
+      if (queryString)
+        url += '?' + queryString;
+
+      // History serializes the state, so we don't push the actual route object.
+      window.history.pushState(this.currentRoute.path, '', url);
+      this.setCurrentRoute(route, params, false);
+    }
+
+    /**
+     * Navigates to the previous route if it has an equal or lesser depth.
+     * If there is no previous route in history meeting those requirements,
+     * this navigates to the immediate parent. This will never exit Settings.
+     */
+    navigateToPreviousRoute() {
+      var previousRoute = window.history.state &&
+          assert(this.getRouteForPath(
+              /** @type {string} */ (window.history.state)));
+
+      if (previousRoute && previousRoute.depth <= this.currentRoute.depth)
+        window.history.back();
+      else
+        this.navigateTo(
+            this.currentRoute.parent ||
+            /** @type {!settings.Route} */ (this.routes_.BASIC));
+    }
+
+    /**
+     * Initialize the route and query params from the URL.
+     */
+    initializeRouteFromUrl() {
+      assert(!this.initializeRouteFromUrlCalled_);
+      this.initializeRouteFromUrlCalled_ = true;
+
+      var route = this.getRouteForPath(window.location.pathname);
+      // Never allow direct navigation to ADVANCED.
+      if (route && route != this.routes_.ADVANCED) {
+        this.currentRoute = route;
+        this.currentQueryParameters_ =
+            new URLSearchParams(window.location.search);
+      } else {
+        window.history.replaceState(undefined, '', this.routes_.BASIC.path);
+      }
+    }
+
+    resetRouteForTesting() {
+      this.initializeRouteFromUrlCalled_ = false;
+      this.wasLastRouteChangePopstate_ = false;
+      this.currentRoute = /** @type {!settings.Route} */ (this.routes_.BASIC);
+      this.currentQueryParameters_ = new URLSearchParams();
+    }
+  }
+
+  var routerInstance = new Router();
 
   var routeObservers = new Set();
 
@@ -257,7 +554,7 @@
 
       // Emulating Polymer data bindings, the observer is called when the
       // element starts observing the route.
-      this.currentRouteChanged(currentRoute, undefined);
+      this.currentRouteChanged(routerInstance.currentRoute, undefined);
     },
 
     /** @override */
@@ -282,155 +579,40 @@
    */
   var CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
 
-  /**
-   * @param {string} path
-   * @return {?settings.Route} The matching canonical route, or null if none
-   *     matches.
-   */
-  var getRouteForPath = function(path) {
-    // Allow trailing slash in paths.
-    var canonicalPath = path.replace(CANONICAL_PATH_REGEX, '$1$2');
-
-    // TODO(tommycli): Use Object.values once Closure compilation supports it.
-    var matchingKey = Object.keys(Route).find(function(key) {
-      return Route[key].path == canonicalPath;
-    });
-
-    return !!matchingKey ? Route[matchingKey] : null;
-  };
-
-  /**
-   * The current active route. This updated is only by settings.navigateTo or
-   * settings.initializeRouteFromUrl.
-   * @private {!settings.Route}
-   */
-  var currentRoute = Route.BASIC;
-
-  /**
-   * The current query parameters. This is updated only by settings.navigateTo
-   * or settings.initializeRouteFromUrl.
-   * @private {!URLSearchParams}
-   */
-  var currentQueryParameters = new URLSearchParams();
-
-  /** @private {boolean} */
-  var wasLastRouteChangePopstate = false;
-
-  /** @private */
-  var initializeRouteFromUrlCalled = false;
-
-  /**
-   * Initialize the route and query params from the URL.
-   */
-  var initializeRouteFromUrl = function() {
-    assert(!initializeRouteFromUrlCalled);
-    initializeRouteFromUrlCalled = true;
-
-    var route = getRouteForPath(window.location.pathname);
-    // Never allow direct navigation to ADVANCED.
-    if (route && route != Route.ADVANCED) {
-      currentRoute = route;
-      currentQueryParameters = new URLSearchParams(window.location.search);
-    } else {
-      window.history.replaceState(undefined, '', Route.BASIC.path);
-    }
-  };
-
-  function resetRouteForTesting() {
-    initializeRouteFromUrlCalled = false;
-    wasLastRouteChangePopstate = false;
-    currentRoute = Route.BASIC;
-    currentQueryParameters = new URLSearchParams();
-  }
-
-  /**
-   * Helper function to set the current route and notify all observers.
-   * @param {!settings.Route} route
-   * @param {!URLSearchParams} queryParameters
-   * @param {boolean} isPopstate
-   */
-  var setCurrentRoute = function(route, queryParameters, isPopstate) {
-    var oldRoute = currentRoute;
-    currentRoute = route;
-    currentQueryParameters = queryParameters;
-    wasLastRouteChangePopstate = isPopstate;
-    routeObservers.forEach(function(observer) {
-      observer.currentRouteChanged(currentRoute, oldRoute);
-    });
-  };
-
-  /** @return {!settings.Route} */
-  var getCurrentRoute = function() {
-    return currentRoute;
-  };
-
-  /** @return {!URLSearchParams} */
-  var getQueryParameters = function() {
-    return new URLSearchParams(currentQueryParameters);  // Defensive copy.
-  };
-
-  /** @return {boolean} */
-  var lastRouteChangeWasPopstate = function() {
-    return wasLastRouteChangePopstate;
-  };
-
-  /**
-   * Navigates to a canonical route and pushes a new history entry.
-   * @param {!settings.Route} route
-   * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same
-   *     URL parameters in a different order will still push to history.
-   * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL
-   *     parameter during navigation. Defaults to false.
-   */
-  var navigateTo = function(route, opt_dynamicParameters, opt_removeSearch) {
-    // The ADVANCED route only serves as a parent of subpages, and should not
-    // be possible to navigate to it directly.
-    if (route == settings.Route.ADVANCED)
-      route = settings.Route.BASIC;
-
-    var params = opt_dynamicParameters || new URLSearchParams();
-    var removeSearch = !!opt_removeSearch;
-
-    var oldSearchParam = getQueryParameters().get('search') || '';
-    var newSearchParam = params.get('search') || '';
-
-    if (!removeSearch && oldSearchParam && !newSearchParam)
-      params.append('search', oldSearchParam);
-
-    var url = route.path;
-    var queryString = params.toString();
-    if (queryString)
-      url += '?' + queryString;
-
-    // History serializes the state, so we don't push the actual route object.
-    window.history.pushState(currentRoute.path, '', url);
-    setCurrentRoute(route, params, false);
-  };
-
-  /**
-   * Navigates to the previous route if it has an equal or lesser depth.
-   * If there is no previous route in history meeting those requirements,
-   * this navigates to the immediate parent. This will never exit Settings.
-   */
-  var navigateToPreviousRoute = function() {
-    var previousRoute = window.history.state &&
-        assert(getRouteForPath(/** @type {string} */ (window.history.state)));
-
-    if (previousRoute && previousRoute.depth <= currentRoute.depth)
-      window.history.back();
-    else
-      navigateTo(currentRoute.parent || Route.BASIC);
-  };
-
   window.addEventListener('popstate', function(event) {
     // On pop state, do not push the state onto the window.history again.
-    setCurrentRoute(
-        getRouteForPath(window.location.pathname) || Route.BASIC,
+    routerInstance.setCurrentRoute(
+        /** @type {!settings.Route} */ (
+            routerInstance.getRouteForPath(window.location.pathname) ||
+            routerInstance.getRoutes().BASIC),
         new URLSearchParams(window.location.search), true);
   });
 
+  // TODO(scottchen): Change to 'get routes() {}' in export when we fix a bug in
+  // ChromePass that limits the syntax of what can be returned from cr.define().
+  var routes = routerInstance.getRoutes();
+
+  // TODO(scottchen): Stop exposing all those methods directly on settings.*,
+  // and instead update all clients to use the singleton instance directly
+  var getCurrentRoute = routerInstance.getCurrentRoute.bind(routerInstance);
+  var getRouteForPath = routerInstance.getRouteForPath.bind(routerInstance);
+  var initializeRouteFromUrl =
+      routerInstance.initializeRouteFromUrl.bind(routerInstance);
+  var resetRouteForTesting =
+      routerInstance.resetRouteForTesting.bind(routerInstance);
+  var getQueryParameters =
+      routerInstance.getQueryParameters.bind(routerInstance);
+  var lastRouteChangeWasPopstate =
+      routerInstance.lastRouteChangeWasPopstate.bind(routerInstance);
+  var navigateTo = routerInstance.navigateTo.bind(routerInstance);
+  var navigateToPreviousRoute =
+      routerInstance.navigateToPreviousRoute.bind(routerInstance);
+
   return {
-    Route: Route,
+    Route: Route,            // The Route class definition.
+    Router: Router,          // The Router class definition.
+    router: routerInstance,  // the singleton.
+    routes: routes,
     RouteObserverBehavior: RouteObserverBehavior,
     getRouteForPath: getRouteForPath,
     initializeRouteFromUrl: initializeRouteFromUrl,
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.js b/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
index f462274..57cf8a0 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
@@ -42,7 +42,7 @@
      */
     subpageRoute: {
       type: Object,
-      value: settings.Route.SEARCH_ENGINES,
+      value: settings.routes.SEARCH_ENGINES,
     },
 
     /** @private {boolean} */
diff --git a/chrome/browser/resources/settings/search_page/search_page.js b/chrome/browser/resources/settings/search_page/search_page.js
index 3ac0946..54d2e83 100644
--- a/chrome/browser/resources/settings/search_page/search_page.js
+++ b/chrome/browser/resources/settings/search_page/search_page.js
@@ -75,8 +75,11 @@
     }.bind(this));
 
     this.focusConfig_ = new Map();
-    this.focusConfig_.set(
-        settings.Route.SEARCH_ENGINES.path, '#subpage-trigger .subpage-arrow');
+    if (settings.routes.SEARCH_ENGINES) {
+      this.focusConfig_.set(
+          settings.routes.SEARCH_ENGINES.path,
+          '#subpage-trigger .subpage-arrow');
+    }
   },
 
   /** @private */
@@ -93,7 +96,7 @@
 
   /** @private */
   onManageSearchEnginesTap_: function() {
-    settings.navigateTo(settings.Route.SEARCH_ENGINES);
+    settings.navigateTo(settings.routes.SEARCH_ENGINES);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index db5ed45..571e807 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -175,7 +175,7 @@
    * @private
    */
   updatePagesShown_: function() {
-    var inAbout = settings.Route.ABOUT.contains(settings.getCurrentRoute());
+    var inAbout = settings.routes.ABOUT.contains(settings.getCurrentRoute());
     this.showPages_ = {about: inAbout, settings: !inAbout};
 
     // Calculate and set the overflow padding.
@@ -235,12 +235,13 @@
    * @return {(?SettingsAboutPageElement|?SettingsBasicPageElement)}
    */
   getPage_: function(route) {
-    if (settings.Route.ABOUT.contains(route)) {
+    if (settings.routes.ABOUT.contains(route)) {
       return /** @type {?SettingsAboutPageElement} */ (
           this.$$('settings-about-page'));
     }
-    if (settings.Route.BASIC.contains(route) ||
-        settings.Route.ADVANCED.contains(route)) {
+    if (settings.routes.BASIC.contains(route) ||
+        (settings.routes.ADVANCED &&
+         settings.routes.ADVANCED.contains(route))) {
       return /** @type {?SettingsBasicPageElement} */ (
           this.$$('settings-basic-page'));
     }
@@ -259,7 +260,7 @@
     return new Promise(function(resolve, reject) {
       setTimeout(function() {
         var whenSearchDone =
-            assert(this.getPage_(settings.Route.BASIC)).searchContents(query);
+            assert(this.getPage_(settings.routes.BASIC)).searchContents(query);
         whenSearchDone.then(function(result) {
           resolve();
           if (result.canceled) {
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
index 7e6b9df..5ff27d5 100644
--- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js
+++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -64,14 +64,14 @@
     if (this.scroller) {
       // When navigating from a section to the root route, we just need to
       // scroll to the top, and can early exit afterwards.
-      if (oldRouteWasSection && newRoute == settings.Route.BASIC) {
+      if (oldRouteWasSection && newRoute == settings.routes.BASIC) {
         this.scroller.scrollTop = 0;
         return;
       }
 
       // When navigating to the About page, we need to scroll to the top, and
       // still do the rest of section management.
-      if (newRoute == settings.Route.ABOUT)
+      if (newRoute == settings.routes.ABOUT)
         this.scroller.scrollTop = 0;
     }
 
@@ -79,8 +79,8 @@
     // in-page back/forward navigations (from a section or the root page).
     // Also always scroll when coming from either the About or root page.
     var scrollToSection = !settings.lastRouteChangeWasPopstate() ||
-        oldRouteWasSection || oldRoute == settings.Route.BASIC ||
-        oldRoute == settings.Route.ABOUT;
+        oldRouteWasSection || oldRoute == settings.routes.BASIC ||
+        oldRoute == settings.routes.ABOUT;
 
     // TODO(dschuyler): This doesn't set the flag in the case of going to or
     // from the main page. It seems sensible to set the flag in those cases,
@@ -161,8 +161,8 @@
         currentSection.scrollIntoView();
       }
     } else if (
-        this.tagName == 'SETTINGS-BASIC-PAGE' &&
-        settings.Route.ADVANCED.contains(currentRoute) &&
+        this.tagName == 'SETTINGS-BASIC-PAGE' && settings.routes.ADVANCED &&
+        settings.routes.ADVANCED.contains(currentRoute) &&
         // Need to exclude routes that correspond to 'non-sectioned' children of
         // ADVANCED, otherwise tryTransitionToSection_ will recurse endlessly.
         !currentRoute.isNavigableDialog) {
@@ -298,7 +298,7 @@
     // Don't animate the collapse if we are transitioning between Basic/Advanced
     // and About, since the section won't be visible.
     var needAnimate =
-        settings.Route.ABOUT.contains(settings.getCurrentRoute()) ==
+        settings.routes.ABOUT.contains(settings.getCurrentRoute()) ==
         (section.domHost.tagName == 'SETTINGS-ABOUT-PAGE');
 
     // Animate the collapse if the section knows the original height, except
diff --git a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
index b2c80e50..d4dd9b9 100644
--- a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
+++ b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
@@ -66,13 +66,18 @@
 
     // Only handle iron-select events from neon-animatable elements and the
     // given whitelist of settings-subpage instances.
-    var whitelist = 'settings-subpage#site-settings, ' +
-        'settings-subpage[route-path=\"' +
-        settings.Route.SITE_SETTINGS_COOKIES.path + '\"]';
+    var whitelist = 'settings-subpage#site-settings';
+
+    if (settings.routes.SITE_SETTINGS_COOKIES) {
+      whitelist += ', settings-subpage[route-path=\"' +
+          settings.routes.SITE_SETTINGS_COOKIES.path + '\"]';
+    }
 
     // <if expr="chromeos">
-    whitelist += ', settings-subpage[route-path=\"' +
-        settings.Route.INTERNET_NETWORKS.path + '\"]';
+    if (settings.routes.INTERNET_NETWORKS) {
+      whitelist += ', settings-subpage[route-path=\"' +
+          settings.routes.INTERNET_NETWORKS.path + '\"]';
+    }
     // </if>
 
     if (!e.detail.item.matches('neon-animatable, ' + whitelist))
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 9439e21..02e7d3f 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -226,7 +226,7 @@
       return;
 
     settings.navigateTo(
-        settings.Route.BASIC,
+        settings.routes.BASIC,
         query.length > 0 ?
             new URLSearchParams('search=' + encodeURIComponent(query)) :
             undefined,
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.js b/chrome/browser/resources/settings/site_settings/all_sites.js
index 4690c783..3ac0f36 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.js
+++ b/chrome/browser/resources/settings/site_settings/all_sites.js
@@ -66,7 +66,7 @@
    */
   onOriginTap_: function(event) {
     settings.navigateTo(
-        settings.Route.SITE_SETTINGS_SITE_DETAILS,
+        settings.routes.SITE_SETTINGS_SITE_DETAILS,
         new URLSearchParams('site=' + event.model.item.origin));
   },
 
diff --git a/chrome/browser/resources/settings/site_settings/site_data.js b/chrome/browser/resources/settings/site_settings/site_data.js
index 690eaab..0d0b1a76 100644
--- a/chrome/browser/resources/settings/site_settings/site_data.js
+++ b/chrome/browser/resources/settings/site_settings/site_data.js
@@ -55,9 +55,11 @@
     // Populate the |focusConfig| map of the parent <settings-animated-pages>
     // element, with additional entries that correspond to subpage trigger
     // elements residing in this element's Shadow DOM.
-    this.focusConfig.set(
-        settings.Route.SITE_SETTINGS_DATA_DETAILS.path,
-        '* /deep/ #filter /deep/ #searchInput');
+    if (settings.routes.SITE_SETTINGS_DATA_DETAILS) {
+      this.focusConfig.set(
+          settings.routes.SITE_SETTINGS_DATA_DETAILS.path,
+          '* /deep/ #filter /deep/ #searchInput');
+    }
   },
 
   /** @override */
@@ -160,7 +162,7 @@
    */
   onSiteTap_: function(event) {
     settings.navigateTo(
-        settings.Route.SITE_SETTINGS_DATA_DETAILS,
+        settings.routes.SITE_SETTINGS_DATA_DETAILS,
         new URLSearchParams('site=' + event.model.item.site));
   },
 });
diff --git a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
index e01f9a8..0e91398 100644
--- a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
+++ b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
@@ -55,7 +55,8 @@
    * @protected
    */
   currentRouteChanged: function(route) {
-    if (settings.getCurrentRoute() != settings.Route.SITE_SETTINGS_DATA_DETAILS)
+    if (settings.getCurrentRoute() !=
+        settings.routes.SITE_SETTINGS_DATA_DETAILS)
       return;
     var site = settings.getQueryParameters().get('site');
     if (!site || site == this.site_)
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index 0cd04db..f53c619 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -315,7 +315,7 @@
     if (!this.enableSiteSettings_)
       return;
     settings.navigateTo(
-        settings.Route.SITE_SETTINGS_SITE_DETAILS,
+        settings.routes.SITE_SETTINGS_SITE_DETAILS,
         new URLSearchParams('site=' + event.model.item.origin));
   },
 
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
index a8cbdab..e07ce92 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
@@ -71,7 +71,7 @@
     // Populate the |focusConfig| map of the parent <settings-animated-pages>
     // element, with additional entries that correspond to subpage trigger
     // elements residing in this element's Shadow DOM.
-    var R = settings.Route;
+    var R = settings.routes;
     [[R.SITE_SETTINGS_COOKIES, 'cookies'],
      [R.SITE_SETTINGS_LOCATION, 'location'], [R.SITE_SETTINGS_CAMERA, 'camera'],
      [R.SITE_SETTINGS_MICROPHONE, 'microphone'],
@@ -173,6 +173,6 @@
    */
   onTapNavigate_: function(event) {
     var dataSet = /** @type {{route: string}} */ (event.currentTarget.dataset);
-    settings.navigateTo(settings.Route[dataSet.route]);
+    settings.navigateTo(settings.routes[dataSet.route]);
   },
 });
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index 3c29971..8409ecf 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -78,6 +78,7 @@
     datatypes.push_back(syncer::SUPERVISED_USER_SETTINGS);
     datatypes.push_back(syncer::SUPERVISED_USER_WHITELISTS);
     datatypes.push_back(syncer::TYPED_URLS);
+    datatypes.push_back(syncer::USER_EVENTS);
 
     return datatypes;
   }
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index dfa37ec6..ab3a5226 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -121,11 +121,14 @@
   }
 
 #if defined(OS_CHROMEOS)
-  size_t playstore_api_group_id =
-      controller->AddGroup(kMaxPlayStoreResults, 1.0);
-  controller->AddProvider(playstore_api_group_id,
-                          base::MakeUnique<ArcPlayStoreSearchProvider>(
-                              kMaxPlayStoreResults, profile, list_controller));
+  if (features::IsPlayStoreAppSearchEnabled()) {
+    size_t playstore_api_group_id =
+        controller->AddGroup(kMaxPlayStoreResults, 1.0);
+    controller->AddProvider(
+        playstore_api_group_id,
+        base::MakeUnique<ArcPlayStoreSearchProvider>(kMaxPlayStoreResults,
+                                                     profile, list_controller));
+  }
 #endif
   return controller;
 }
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 4c5465b..f21843c 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/signin_error_notifier_factory_ash.h"
 #include "chrome/browser/speech/tts_controller.h"
 #include "chrome/browser/sync/sync_error_notifier_factory_ash.h"
@@ -50,6 +49,7 @@
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/palette_delegate_chromeos.h"
+#include "chrome/browser/ui/ash/session_controller_client.h"
 #include "chrome/browser/ui/ash/session_util.h"
 #include "chrome/browser/ui/ash/system_tray_delegate_chromeos.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
@@ -406,28 +406,7 @@
 }
 
 bool ChromeShellDelegate::IsMultiProfilesEnabled() const {
-  if (!profiles::IsMultipleProfilesEnabled())
-    return false;
-  // If there is a user manager, we need to see that we can at least have 2
-  // simultaneous users to allow this feature.
-  if (!user_manager::UserManager::IsInitialized())
-    return false;
-  size_t admitted_users_to_be_added =
-      user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile().size();
-  size_t logged_in_users =
-      user_manager::UserManager::Get()->GetLoggedInUsers().size();
-  if (!logged_in_users) {
-    // The shelf gets created on the login screen and as such we have to create
-    // all multi profile items of the the system tray menu before the user logs
-    // in. For special cases like Kiosk mode and / or guest mode this isn't a
-    // problem since either the browser gets restarted and / or the flag is not
-    // allowed, but for an "ephermal" user (see crbug.com/312324) it is not
-    // decided yet if they could add other users to their session or not.
-    // TODO(skuhne): As soon as the issue above needs to be resolved, this logic
-    // should change.
-    logged_in_users = 1;
-  }
-  return admitted_users_to_be_added + logged_in_users > 1;
+  return SessionControllerClient::IsMultiProfileEnabled();
 }
 
 bool ChromeShellDelegate::IsIncognitoAllowed() const {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 6535032..cf195728 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -1327,7 +1327,7 @@
 }
 
 // Check the launcher activation state for applications and browser.
-IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, DISABLED_ActivationStateCheck) {
+IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ActivationStateCheck) {
   TabStripModel* tab_strip = browser()->tab_strip_model();
   // Get the browser item index
   int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 8b26869..1522e69 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -16,13 +16,18 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
+#include "chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/user_switch_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/theme_resources.h"
@@ -31,6 +36,7 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
+#include "components/user_manager/user_type.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
@@ -113,6 +119,14 @@
   UserManager::Get()->SwitchActiveUser(account_id);
 }
 
+// Callback for the dialog that warns the user about multi-profile, which has
+// a "never show again" checkbox.
+void OnAcceptMultiProfileIntro(bool never_show_again) {
+  PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
+  prefs->SetBoolean(prefs::kMultiProfileNeverShowIntro, never_show_again);
+  chromeos::UserAddingScreen::Get()->Start();
+}
+
 }  // namespace
 
 namespace mojo {
@@ -215,6 +229,67 @@
   DoCycleActiveUser(direction);
 }
 
+void SessionControllerClient::ShowMultiProfileLogin() {
+  if (!IsMultiProfileEnabled())
+    return;
+
+  // Only regular non-supervised users could add other users to current session.
+  if (UserManager::Get()->GetActiveUser()->GetType() !=
+      user_manager::USER_TYPE_REGULAR) {
+    return;
+  }
+
+  if (UserManager::Get()->GetLoggedInUsers().size() >=
+      session_manager::kMaxmiumNumberOfUserSessions) {
+    return;
+  }
+
+  // Launch sign in screen to add another user to current session.
+  if (!UserManager::Get()->GetUsersAllowedForMultiProfile().empty()) {
+    // Don't show the dialog if any logged-in user in the multi-profile session
+    // dismissed it.
+    bool show_intro = true;
+    const user_manager::UserList logged_in_users =
+        UserManager::Get()->GetLoggedInUsers();
+    for (User* user : logged_in_users) {
+      show_intro &=
+          !multi_user_util::GetProfileFromAccountId(user->GetAccountId())
+               ->GetPrefs()
+               ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
+      if (!show_intro)
+        break;
+    }
+    if (show_intro) {
+      base::Callback<void(bool)> on_accept =
+          base::Bind(&OnAcceptMultiProfileIntro);
+      chromeos::ShowMultiprofilesIntroDialog(on_accept);
+    } else {
+      chromeos::UserAddingScreen::Get()->Start();
+    }
+  }
+}
+
+// static
+bool SessionControllerClient::IsMultiProfileEnabled() {
+  if (!profiles::IsMultipleProfilesEnabled() || !UserManager::IsInitialized())
+    return false;
+  size_t admitted_users_to_be_added =
+      UserManager::Get()->GetUsersAllowedForMultiProfile().size();
+  size_t logged_in_users = UserManager::Get()->GetLoggedInUsers().size();
+  if (logged_in_users == 0) {
+    // The shelf gets created on the login screen and as such we have to create
+    // all multi profile items of the the system tray menu before the user logs
+    // in. For special cases like Kiosk mode and / or guest mode this isn't a
+    // problem since either the browser gets restarted and / or the flag is not
+    // allowed, but for an "ephermal" user (see crbug.com/312324) it is not
+    // decided yet if they could add other users to their session or not.
+    // TODO(skuhne): As soon as the issue above needs to be resolved, this logic
+    // should change.
+    logged_in_users = 1;
+  }
+  return (admitted_users_to_be_added + logged_in_users) > 1;
+}
+
 void SessionControllerClient::ActiveUserChanged(const User* active_user) {
   SendSessionInfoIfChanged();
 
diff --git a/chrome/browser/ui/ash/session_controller_client.h b/chrome/browser/ui/ash/session_controller_client.h
index 7bfcc6c3..82e30c2 100644
--- a/chrome/browser/ui/ash/session_controller_client.h
+++ b/chrome/browser/ui/ash/session_controller_client.h
@@ -69,6 +69,9 @@
   void RequestLockScreen() override;
   void SwitchActiveUser(const AccountId& account_id) override;
   void CycleActiveUser(ash::CycleUserDirection direction) override;
+  void ShowMultiProfileLogin() override;
+
+  static bool IsMultiProfileEnabled();
 
   // user_manager::UserManager::UserSessionStateObserver:
   void ActiveUserChanged(const user_manager::User* active_user) override;
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index 0db2e059..b74be5a 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -232,6 +232,10 @@
   system_tray_->SetPrimaryTrayVisible(visible);
 }
 
+void SystemTrayClient::SetPerformanceTracingIconVisible(bool visible) {
+  system_tray_->SetPerformanceTracingIconVisible(visible);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ash::mojom::SystemTrayClient:
 
diff --git a/chrome/browser/ui/ash/system_tray_client.h b/chrome/browser/ui/ash/system_tray_client.h
index 1237ff224..8f6cf93 100644
--- a/chrome/browser/ui/ash/system_tray_client.h
+++ b/chrome/browser/ui/ash/system_tray_client.h
@@ -54,6 +54,7 @@
   // Wrappers around ash::mojom::SystemTray interface:
   void SetPrimaryTrayEnabled(bool enabled);
   void SetPrimaryTrayVisible(bool visible);
+  void SetPerformanceTracingIconVisible(bool visible);
 
   // ash::mojom::SystemTrayClient:
   void ShowSettings() override;
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index f96eb3f..ee28440 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -30,12 +30,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/events/system_key_event_listener.h"
-#include "chrome/browser/chromeos/login/login_wizard.h"
-#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
-#include "chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/networking_config_delegate_chromeos.h"
 #include "chrome/browser/ui/ash/system_tray_client.h"
 #include "chrome/browser/ui/browser.h"
@@ -51,9 +46,6 @@
 #include "components/google/core/browser/google_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/core/session_manager.h"
-#include "components/user_manager/user.h"
-#include "components/user_manager/user_manager.h"
-#include "components/user_manager/user_type.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -62,16 +54,6 @@
 
 namespace chromeos {
 
-namespace {
-
-void OnAcceptMultiprofilesIntro(bool no_show_again) {
-  PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
-  prefs->SetBoolean(prefs::kMultiProfileNeverShowIntro, no_show_again);
-  UserAddingScreen::Get()->Start();
-}
-
-}  // namespace
-
 SystemTrayDelegateChromeOS::SystemTrayDelegateChromeOS()
     : networking_config_delegate_(
           base::MakeUnique<NetworkingConfigDelegateChromeos>()) {
@@ -120,50 +102,6 @@
     DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
 }
 
-void SystemTrayDelegateChromeOS::ShowUserLogin() {
-  if (!ash::Shell::Get()->shell_delegate()->IsMultiProfilesEnabled())
-    return;
-
-  // Only regular non-supervised users could add other users to current session.
-  if (user_manager::UserManager::Get()->GetActiveUser()->GetType() !=
-      user_manager::USER_TYPE_REGULAR) {
-    return;
-  }
-
-  if (user_manager::UserManager::Get()->GetLoggedInUsers().size() >=
-      session_manager::kMaxmiumNumberOfUserSessions) {
-    return;
-  }
-
-  // Launch sign in screen to add another user to current session.
-  if (user_manager::UserManager::Get()
-          ->GetUsersAllowedForMultiProfile()
-          .size()) {
-    // Don't show dialog if any logged in user in multi-profiles session
-    // dismissed it.
-    bool show_intro = true;
-    const user_manager::UserList logged_in_users =
-        user_manager::UserManager::Get()->GetLoggedInUsers();
-    for (user_manager::UserList::const_iterator it = logged_in_users.begin();
-         it != logged_in_users.end();
-         ++it) {
-      show_intro &=
-          !multi_user_util::GetProfileFromAccountId((*it)->GetAccountId())
-               ->GetPrefs()
-               ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
-      if (!show_intro)
-        break;
-    }
-    if (show_intro) {
-      base::Callback<void(bool)> on_accept =
-          base::Bind(&OnAcceptMultiprofilesIntro);
-      ShowMultiprofilesIntroDialog(on_accept);
-    } else {
-      UserAddingScreen::Get()->Start();
-    }
-  }
-}
-
 ash::NetworkingConfigDelegate*
 SystemTrayDelegateChromeOS::GetNetworkingConfigDelegate() const {
   return networking_config_delegate_.get();
@@ -217,14 +155,9 @@
       prefs::kShouldAlwaysShowAccessibilityMenu,
       base::Bind(&SystemTrayDelegateChromeOS::OnAccessibilityModeChanged,
                  base::Unretained(this), ash::A11Y_NOTIFICATION_NONE));
-  user_pref_registrar_->Add(
-      prefs::kPerformanceTracingEnabled,
-      base::Bind(&SystemTrayDelegateChromeOS::UpdatePerformanceTracing,
-                 base::Unretained(this)));
 
   UpdateShowLogoutButtonInTray();
   UpdateLogoutDialogDuration();
-  UpdatePerformanceTracing();
   search_key_mapped_to_ =
       profile->GetPrefs()->GetInteger(prefs::kLanguageRemapSearchKeyTo);
 }
@@ -324,14 +257,6 @@
   GetSystemTrayNotifier()->NotifyAccessibilityModeChanged(notify);
 }
 
-void SystemTrayDelegateChromeOS::UpdatePerformanceTracing() {
-  if (!user_pref_registrar_)
-    return;
-  bool value = user_pref_registrar_->prefs()->GetBoolean(
-      prefs::kPerformanceTracingEnabled);
-  GetSystemTrayNotifier()->NotifyTracingModeChanged(value);
-}
-
 // Overridden from chrome::BrowserListObserver.
 void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) {
   NotifyIfLastWindowClosed();
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
index f9712ac..1b11f9a8 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -43,7 +43,6 @@
 
   // Overridden from ash::SystemTrayDelegate:
   void Initialize() override;
-  void ShowUserLogin() override;
   ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() const override;
   void ActiveUserWasChanged() override;
   bool IsSearchKeyMappedToCapsLock() override;
@@ -79,8 +78,6 @@
   void OnAccessibilityModeChanged(
       ash::AccessibilityNotificationVisibility notify);
 
-  void UpdatePerformanceTracing();
-
   // Overridden from chrome::BrowserListObserver:
   void OnBrowserRemoved(Browser* browser) override;
 
diff --git a/chrome/browser/ui/autofill/popup_constants.h b/chrome/browser/ui/autofill/popup_constants.h
index c2f6ed0..a7a2d683 100644
--- a/chrome/browser/ui/autofill/popup_constants.h
+++ b/chrome/browser/ui/autofill/popup_constants.h
@@ -9,12 +9,12 @@
 
 namespace autofill {
 
-#if defined(TOOLKIT_VIEWS)
-// In views, the implementation takes care of the border itself.
-const int kPopupBorderThickness = 0;
-#else
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
 // TODO(crbug.com/676221): Change this to pixels
 const int kPopupBorderThickness = 1;
+#else
+// In views, the implementation takes care of the border itself.
+const int kPopupBorderThickness = 0;
 #endif
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index ce61c46c..6f6b060b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -344,7 +344,7 @@
 
   // viewDidLoad became part of the API in 10.10.
   if (!base::mac::IsAtLeastOS10_10())
-    [self viewDidLoad];
+    [self viewDidLoadImpl];
 }
 
 - (BookmarkButton*)findAncestorButtonOnBarForNode:(const BookmarkNode*)node {
@@ -459,6 +459,12 @@
 }
 
 - (void)viewDidLoad {
+  // This indirection allows the viewDidLoad implementation to be called from
+  // elsewhere without triggering an availability warning.
+  [self viewDidLoadImpl];
+}
+
+- (void)viewDidLoadImpl {
   // We are enabled by default.
   barIsEnabled_ = YES;
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
index 2694ed0..9179b67 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa_unittest.mm
@@ -130,7 +130,7 @@
 
 // Fake a controller for callback ponging
 
-- (void)viewDidLoad {
+- (void)viewDidLoadImpl {
   // no-op
 }
 
diff --git a/chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.mm b/chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.mm
index f881d164..076a2d1 100644
--- a/chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.mm
+++ b/chrome/browser/ui/cocoa/fullscreen_low_power_coordinator.mm
@@ -30,12 +30,13 @@
   NSRect screenFrame = [[eventTargetWindow screen] frame];
   NSRect initialRect = NSMakeRect(
       0, 0, NSWidth(screenFrame), NSHeight(screenFrame));
-  if (self = [super
-          initWithContentRect:initialRect
-                    styleMask:NSTitledWindowMask | NSResizableWindowMask |
-                              NSFullSizeContentViewWindowMask
-                      backing:NSBackingStoreBuffered
-                        defer:NO]) {
+  auto mask = NSTitledWindowMask | NSResizableWindowMask;
+  if (@available(macOS 10.10, *))
+    mask |= NSFullSizeContentViewWindowMask;
+  if (self = [super initWithContentRect:initialRect
+                              styleMask:mask
+                                backing:NSBackingStoreBuffered
+                                  defer:NO]) {
     eventTargetWindow_.reset(eventTargetWindow, base::scoped_policy::RETAIN);
     [self setCollectionBehavior:NSWindowCollectionBehaviorIgnoresCycle];
     [self setExcludedFromWindowsMenu:YES];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index 06775bb..a0b4a5e 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -107,7 +107,9 @@
   const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
   bool hasCustomThemeImage = themeProvider &&
       themeProvider->HasCustomImage(IDR_THEME_FRAME);
-  BOOL supportsVibrancy = [self visualEffectView] != nil;
+  BOOL supportsVibrancy = false;
+  if (@available(macOS 10.10, *))
+    supportsVibrancy = [self visualEffectView] != nil;
   BOOL isMainWindow = [[self window] isMainWindow];
 
   // If in Material Design mode, decrease the tabstrip background's translucency
@@ -353,7 +355,8 @@
   newTabButton_.reset([button retain]);
 }
 
-- (NSVisualEffectView*)visualEffectView {
+- (NSVisualEffectView*)visualEffectView
+    __attribute__((availability(macos, introduced = 10.10))) {
   return [[BrowserWindowController
       browserWindowControllerForWindow:[self window]] visualEffectView];
 }
@@ -367,21 +370,24 @@
 
   // Finish configuring the NSVisualEffectView so that it matches the window's
   // theme.
-  NSVisualEffectView* visualEffectView = [self visualEffectView];
-  const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
-  if (!visualEffectView || !themeProvider) {
-    return;
-  }
+  if (@available(macOS 10.10, *)) {
+    NSVisualEffectView* visualEffectView = [self visualEffectView];
+    const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
+    if (!visualEffectView || !themeProvider) {
+      return;
+    }
 
-  // Themes with custom frame images don't use vibrancy. Otherwise, if Incognito
-  // use Material Dark.
-  if (themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
-      themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
-    [visualEffectView setState:NSVisualEffectStateInactive];
-  } else if (themeProvider->InIncognitoMode()) {
-    [visualEffectView setMaterial:NSVisualEffectMaterialDark];
-    [visualEffectView setAppearance:
-        [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
+    // Themes with custom frame images don't use vibrancy. Otherwise, if
+    // Incognito use Material Dark.
+    if (themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
+        themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
+      [visualEffectView setState:NSVisualEffectStateInactive];
+    } else if (themeProvider->InIncognitoMode()) {
+      [visualEffectView setMaterial:NSVisualEffectMaterialDark];
+      [visualEffectView
+          setAppearance:[NSAppearance
+                            appearanceNamed:NSAppearanceNameVibrantDark]];
+    }
   }
 }
 
@@ -402,20 +408,22 @@
 }
 
 - (void)updateVisualEffectState {
-  // Configure the NSVisualEffectView so that it does nothing if the user has
-  // switched to a custom theme, or uses vibrancy if the user has switched back
-  // to the default theme.
-  NSVisualEffectView* visualEffectView = [self visualEffectView];
-  const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
-  if (!visualEffectView || !themeProvider) {
-    return;
-  }
-  if (visualEffectsDisabledForFullscreen_ ||
-      themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
-      themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
-    [visualEffectView setState:NSVisualEffectStateInactive];
-  } else {
-    [visualEffectView setState:NSVisualEffectStateFollowsWindowActiveState];
+  if (@available(macOS 10.10, *)) {
+    // Configure the NSVisualEffectView so that it does nothing if the user has
+    // switched to a custom theme, or uses vibrancy if the user has switched
+    // back to the default theme.
+    NSVisualEffectView* visualEffectView = [self visualEffectView];
+    const ui::ThemeProvider* themeProvider = [[self window] themeProvider];
+    if (!visualEffectView || !themeProvider) {
+      return;
+    }
+    if (visualEffectsDisabledForFullscreen_ ||
+        themeProvider->HasCustomImage(IDR_THEME_FRAME) ||
+        themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) {
+      [visualEffectView setState:NSVisualEffectStateInactive];
+    } else {
+      [visualEffectView setState:NSVisualEffectStateFollowsWindowActiveState];
+    }
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index 047226a4..1ffa5bf 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -242,7 +242,7 @@
 
     [self setWantsLayer:YES];  // -drawFill: needs a layer.
 
-    if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) {
+    if (@available(macOS 10.10, *)) {
       NSNotificationCenter* center =
           [[NSWorkspace sharedWorkspace] notificationCenter];
       [center
@@ -259,7 +259,7 @@
 - (void)dealloc {
   // Cancel any delayed requests that may still be pending (drags or hover).
   [NSObject cancelPreviousPerformRequestsWithTarget:self];
-  if (&NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification) {
+  if (@available(macOS 10.10, *)) {
     NSNotificationCenter* center =
         [[NSWorkspace sharedWorkspace] notificationCenter];
     [center removeObserver:self];
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
index c088f4e1..fba29da 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -29,7 +29,9 @@
   base::scoped_nsobject<NSView> tabStripBackgroundView_;
 
   // Used to blur the titlebar. nil if window does not have titlebar.
-  base::scoped_nsobject<NSVisualEffectView> visualEffectView_;
+  __attribute__((availability(macos, introduced = 10.10)))
+  base::scoped_nsobject<NSVisualEffectView>
+      visualEffectView_;
 
   // The tab strip overlaps the titlebar of the window.
   base::scoped_nsobject<TabStripView> tabStripView_;
@@ -51,7 +53,10 @@
   base::scoped_nsobject<FocusTracker> focusBeforeOverlay_;
   BOOL closeDeferred_;  // If YES, call performClose: in removeOverlay:.
 }
-@property(readonly, nonatomic) NSVisualEffectView* visualEffectView;
+
+@property(readonly, nonatomic)
+    __attribute__((availability(macos, introduced=10.10)))
+    NSVisualEffectView* visualEffectView;
 @property(readonly, nonatomic) NSView* tabStripBackgroundView;
 @property(readonly, nonatomic) TabStripView* tabStripView;
 @property(readonly, nonatomic) FastResizeView* tabContentArea;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index 368f4e5..b524fd3 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -426,63 +426,64 @@
 
   // In Material Design on 10.10 and higher, the top portion of the window is
   // blurred using an NSVisualEffectView.
-  Class nsVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
-  if (!nsVisualEffectViewClass) {
+  if (@available(macOS 10.10, *)) {
+    [window setTitlebarAppearsTransparent:YES];
+
+    // If the window has a normal titlebar, then do not add NSVisualEffectView.
+    if (hasTitleBar)
+      return;
+
+    // NSVisualEffectView provides hints about text anti-aliasing that are wrong
+    // when anything is drawn over it (like a tint or theme image). Wrapping it
+    // stops it from being used for hints. See https://crbug.com/593835.
+    NSView* visualEffectWrapperView = [[[NSView alloc]
+        initWithFrame:[tabStripBackgroundView_ frame]] autorelease];
+
+    visualEffectView_.reset([[NSVisualEffectView alloc]
+        initWithFrame:visualEffectWrapperView.bounds]);
+    DCHECK(visualEffectView_);
+
+    [visualEffectWrapperView
+        setAutoresizingMask:[tabStripBackgroundView_ autoresizingMask]];
+    [visualEffectView_
+        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+    [tabStripBackgroundView_
+        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
+    // Set to a default appearance and material. If this is an Incognito window
+    // the material and vibrancy should be dark but this method gets called at
+    // the start of -[BrowserWindowController initWithBrowser:takeOwnership:],
+    // before the |browser_| ivar has been set. Without a browser object we
+    // can't check the window's theme. The final setup happens in
+    // -[TabStripView setController:], at which point we have access to the
+    // theme.
+    [visualEffectView_
+        setAppearance:[NSAppearance
+                          appearanceNamed:NSAppearanceNameVibrantLight]];
+    [visualEffectView_ setMaterial:NSVisualEffectMaterialLight];
+    [visualEffectView_ setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
+    [visualEffectView_ setState:NSVisualEffectStateFollowsWindowActiveState];
+
+    [visualEffectWrapperView addSubview:visualEffectView_];
+
+    if (chrome::ShouldUseFullSizeContentView()) {
+      [[window contentView] addSubview:visualEffectWrapperView];
+    } else {
+      [rootView addSubview:visualEffectWrapperView
+                positioned:NSWindowBelow
+                relativeTo:nil];
+    }
+
+    // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView.
+    [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]];
+    [visualEffectView_ addSubview:tabStripBackgroundView_];
+  } else {
     DCHECK(!chrome::ShouldUseFullSizeContentView());
     [rootView addSubview:tabStripBackgroundView_
               positioned:NSWindowBelow
               relativeTo:nil];
     return;
   }
-
-  [window setTitlebarAppearsTransparent:YES];
-
-  // If the window has a normal titlebar, then do not add NSVisualEffectView.
-  if (hasTitleBar)
-    return;
-
-  // NSVisualEffectView provides hints about text anti-aliasing that are wrong
-  // when anything is drawn over it (like a tint or theme image). Wrapping it
-  // stops it from being used for hints. See https://crbug.com/593835.
-  NSView* visualEffectWrapperView = [[[NSView alloc]
-      initWithFrame:[tabStripBackgroundView_ frame]] autorelease];
-
-  visualEffectView_.reset([[nsVisualEffectViewClass alloc]
-      initWithFrame:visualEffectWrapperView.bounds]);
-  DCHECK(visualEffectView_);
-
-  [visualEffectWrapperView
-      setAutoresizingMask:[tabStripBackgroundView_ autoresizingMask]];
-  [visualEffectView_
-      setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-  [tabStripBackgroundView_
-      setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
-  // Set to a default appearance and material. If this is an Incognito window
-  // the material and vibrancy should be dark but this method gets called at
-  // the start of -[BrowserWindowController initWithBrowser:takeOwnership:],
-  // before the |browser_| ivar has been set. Without a browser object we
-  // can't check the window's theme. The final setup happens in
-  // -[TabStripView setController:], at which point we have access to the theme.
-  [visualEffectView_ setAppearance:
-      [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
-  [visualEffectView_ setMaterial:NSVisualEffectMaterialLight];
-  [visualEffectView_ setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
-  [visualEffectView_ setState:NSVisualEffectStateFollowsWindowActiveState];
-
-  [visualEffectWrapperView addSubview:visualEffectView_];
-
-  if (chrome::ShouldUseFullSizeContentView()) {
-    [[window contentView] addSubview:visualEffectWrapperView];
-  } else {
-    [rootView addSubview:visualEffectWrapperView
-              positioned:NSWindowBelow
-              relativeTo:nil];
-  }
-
-  // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView.
-  [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]];
-  [visualEffectView_ addSubview:tabStripBackgroundView_];
 }
 
 // Called when the size of the window content area has changed. Override to
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index f5feee6..47814dc 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -248,10 +248,14 @@
 // reason is not guaranteed to be called (http://crbug.com/526276), so implement
 // both.
 - (void)awakeFromNib {
-  [self viewDidLoad];
+  [self viewDidLoadImpl];
 }
 
 - (void)viewDidLoad {
+  [self viewDidLoadImpl];
+}
+
+- (void)viewDidLoadImpl {
   // Temporary: collect information about a potentially missing or inaccessible
   // nib (https://crbug.com/685985)
   NSString* nibPath = [self.nibBundle pathForResource:@"Toolbar" ofType:@"nib"];
diff --git a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
index 684c733e..cfa1818 100644
--- a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
+++ b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
@@ -9,6 +9,8 @@
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/media/router/event_page_request_manager.h"
+#include "chrome/browser/media/router/event_page_request_manager_factory.h"
 #include "chrome/browser/media/router/media_router_factory.h"
 #include "chrome/browser/media/router/mojo/media_router_mojo_impl.h"
 #include "chrome/browser/profiles/profile.h"
@@ -182,17 +184,15 @@
 void MediaRouterContextualMenu::ReportIssue() {
   // Opens feedback page loaded from the media router extension.
   // This is temporary until feedback UI is redesigned.
-  // TODO(crbug.com/597778): remove reference to MediaRouterMojoImpl
-  media_router::MediaRouterMojoImpl* media_router =
-      static_cast<media_router::MediaRouterMojoImpl*>(
-          media_router::MediaRouterFactory::GetApiForBrowserContext(
-              static_cast<content::BrowserContext*>(browser_->profile())));
-  if (media_router->media_route_provider_extension_id().empty())
+  media_router::EventPageRequestManager* request_manager =
+      media_router::EventPageRequestManagerFactory::GetApiForBrowserContext(
+          browser_->profile());
+  if (request_manager->media_route_provider_extension_id().empty())
     return;
-  std::string feedback_url(extensions::kExtensionScheme +
-                           std::string(url::kStandardSchemeSeparator) +
-                           media_router->media_route_provider_extension_id() +
-                           "/feedback.html");
+  std::string feedback_url(
+      extensions::kExtensionScheme +
+      std::string(url::kStandardSchemeSeparator) +
+      request_manager->media_route_provider_extension_id() + "/feedback.html");
   chrome::ShowSingletonTab(browser_, GURL(feedback_url));
 }
 
diff --git a/chrome/browser/ui/webui/cast/cast_ui.cc b/chrome/browser/ui/webui/cast/cast_ui.cc
index 13d5e2c..68f113b 100644
--- a/chrome/browser/ui/webui/cast/cast_ui.cc
+++ b/chrome/browser/ui/webui/cast/cast_ui.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/ui/webui/cast/cast_ui.h"
 
-#include "chrome/browser/media/router/media_router_factory.h"
-#include "chrome/browser/media/router/mojo/media_router_mojo_impl.h"
+#include "chrome/browser/media/router/event_page_request_manager.h"
+#include "chrome/browser/media/router/event_page_request_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -16,11 +16,11 @@
 CastUI::CastUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui) {
   // Retrieve the ID of the component extension.
-  // TODO(crbug.com/597778): remove reference to MediaRouterMojoImpl.
-  auto* router = static_cast<media_router::MediaRouterMojoImpl*>(
-      media_router::MediaRouterFactory::GetApiForBrowserContext(
-          web_ui->GetWebContents()->GetBrowserContext()));
-  std::string extension_id = router->media_route_provider_extension_id();
+  auto* event_page_request_manager =
+      media_router::EventPageRequestManagerFactory::GetApiForBrowserContext(
+          web_ui->GetWebContents()->GetBrowserContext());
+  std::string extension_id =
+      event_page_request_manager->media_route_provider_extension_id();
 
   // Set up the chrome://cast data source and add required resources.
   content::WebUIDataSource* html_source =
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 2e1dd19..9e9a644b 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -370,7 +370,7 @@
   if (url.host() == chrome::kChromeUIQuotaInternalsHost)
     return &NewWebUI<QuotaInternalsUI>;
   if (url.host() == safe_browsing::kChromeUISafeBrowsingHost)
-    return &NewWebUI<SafeBrowsingUI>;
+    return &NewWebUI<safe_browsing::SafeBrowsingUI>;
   if (url.host() == chrome::kChromeUISignInInternalsHost)
     return &NewWebUI<SignInInternalsUI>;
   if (url.host_piece() == chrome::kChromeUISuggestionsHost)
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 369bcbe..679cf901b 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -18,6 +18,8 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/create_presentation_connection_request.h"
+#include "chrome/browser/media/router/event_page_request_manager.h"
+#include "chrome/browser/media/router/event_page_request_manager_factory.h"
 #include "chrome/browser/media/router/issues_observer.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_router_factory.h"
@@ -230,9 +232,11 @@
 
   content::WebContents* wc = web_ui->GetWebContents();
   DCHECK(wc);
+  content::BrowserContext* context = wc->GetBrowserContext();
 
-  router_ =
-      MediaRouterFactory::GetApiForBrowserContext(wc->GetBrowserContext());
+  router_ = MediaRouterFactory::GetApiForBrowserContext(context);
+  event_page_request_manager_ =
+      EventPageRequestManagerFactory::GetApiForBrowserContext(context);
 
   // Allows UI to load extensionview.
   // TODO(haibinlu): limit object-src to current extension once crbug/514866
@@ -858,9 +862,7 @@
 }
 
 const std::string& MediaRouterUI::GetRouteProviderExtensionId() const {
-  // TODO(crbug.com/597778): remove reference to MediaRouterMojoImpl
-  return static_cast<MediaRouterMojoImpl*>(router_)
-      ->media_route_provider_extension_id();
+  return event_page_request_manager_->media_route_provider_extension_id();
 }
 
 void MediaRouterUI::SetUIInitializationTimer(const base::Time& start_time) {
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index bc58d4d4..bb70fa4 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -44,6 +44,7 @@
 namespace media_router {
 
 class CreatePresentationConnectionRequest;
+class EventPageRequestManager;
 class IssuesObserver;
 class MediaRoute;
 class MediaRouter;
@@ -414,6 +415,9 @@
   // Pointer to the MediaRouter for this instance's BrowserContext.
   MediaRouter* router_;
 
+  // Request manager for the Media Router component extension.
+  const EventPageRequestManager* event_page_request_manager_;
+
   // The start time for UI initialization metrics timer. When a dialog has been
   // been painted and initialized with initial data, this should be cleared.
   base::Time start_time_;
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 7ab14c99..c03a049 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -42,11 +42,11 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_transaction_factory.h"
+#include "net/log/file_net_log_observer.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source_type.h"
 #include "net/log/net_log_with_source.h"
-#include "net/log/write_to_file_net_log_observer.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/request_handler_util.h"
 #include "net/url_request/url_request_context.h"
@@ -91,6 +91,11 @@
              ttl);
 }
 
+struct WriteNetLogState {
+  base::ScopedTempDir temp_directory;
+  base::FilePath log_path;
+};
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -140,14 +145,17 @@
   // Closes an incognito browser created with CreateIncognitoBrowser.
   void CloseIncognitoBrowser(const base::ListValue* list_value);
 
-  // Creates a simple log using WriteToFileNetLogObserver, and returns it to
-  // the Javascript callback.
+  // Creates a simple NetLog and returns it to the Javascript callback.
   void GetNetLogFileContents(const base::ListValue* list_value);
 
   // Changes the data reduction proxy mode. A boolean is assumed to exist at
   // index 0 which enables the proxy is set to true.
   void EnableDataReductionProxy(const base::ListValue* list_value);
 
+  // Called after the NetLog started by GetNetLogFileContents() has been written
+  // to disk. Responds to the Javascript caller with the log contents.
+  void OnFinishedWritingNetLog(std::unique_ptr<WriteNetLogState> state);
+
   Browser* browser() { return net_internals_test_->browser(); }
 
   NetInternalsTest* net_internals_test_;
@@ -292,37 +300,37 @@
 void NetInternalsTest::MessageHandler::GetNetLogFileContents(
     const base::ListValue* list_value) {
   base::ThreadRestrictions::ScopedAllowIO allow_io;
-  base::ScopedTempDir temp_directory;
-  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
-  base::FilePath temp_file;
-  ASSERT_TRUE(
-      base::CreateTemporaryFileInDir(temp_directory.GetPath(), &temp_file));
-  base::ScopedFILE temp_file_handle(base::OpenFile(temp_file, "w"));
-  ASSERT_TRUE(temp_file_handle);
+
+  std::unique_ptr<WriteNetLogState> state =
+      base::MakeUnique<WriteNetLogState>();
+
+  ASSERT_TRUE(state->temp_directory.CreateUniqueTempDir());
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(state->temp_directory.GetPath(),
+                                             &state->log_path));
 
   std::unique_ptr<base::Value> constants(net_log::ChromeNetLog::GetConstants(
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
       chrome::GetChannelString()));
-  std::unique_ptr<net::WriteToFileNetLogObserver> net_log_logger(
-      new net::WriteToFileNetLogObserver());
+
+  std::unique_ptr<net::FileNetLogObserver> net_log_logger =
+      net::FileNetLogObserver::CreateUnbounded(state->log_path,
+                                               std::move(constants));
+
   net_log_logger->StartObserving(g_browser_process->net_log(),
-                                 std::move(temp_file_handle), constants.get(),
-                                 nullptr);
+                                 net::NetLogCaptureMode::Default());
+
   g_browser_process->net_log()->AddGlobalEntry(
       net::NetLogEventType::NETWORK_IP_ADDRESSES_CHANGED);
   net::NetLogWithSource net_log_with_source = net::NetLogWithSource::Make(
       g_browser_process->net_log(), net::NetLogSourceType::URL_REQUEST);
   net_log_with_source.BeginEvent(net::NetLogEventType::REQUEST_ALIVE);
-  net_log_logger->StopObserving(nullptr);
-  net_log_logger.reset();
 
-  std::string log_contents;
-  ASSERT_TRUE(base::ReadFileToString(temp_file, &log_contents));
-  ASSERT_GT(log_contents.length(), 0u);
-
-  std::unique_ptr<base::Value> log_contents_value(
-      new base::Value(log_contents));
-  RunJavascriptCallback(log_contents_value.get());
+  // Call OnFinishedWritingNetLog() once net_log_logger has completed writing it
+  // to disk.
+  net_log_logger->StopObserving(
+      nullptr,
+      base::Bind(&NetInternalsTest::MessageHandler::OnFinishedWritingNetLog,
+                 base::Unretained(this), base::Passed(std::move(state))));
 }
 
 void NetInternalsTest::MessageHandler::EnableDataReductionProxy(
@@ -333,6 +341,21 @@
       prefs::kDataSaverEnabled, enable);
 }
 
+void NetInternalsTest::MessageHandler::OnFinishedWritingNetLog(
+    std::unique_ptr<WriteNetLogState> state) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  std::string log_contents;
+  ASSERT_TRUE(base::ReadFileToString(state->log_path, &log_contents));
+  ASSERT_GT(log_contents.length(), 0u);
+
+  std::unique_ptr<base::Value> log_contents_value(
+      new base::Value(log_contents));
+  RunJavascriptCallback(log_contents_value.get());
+
+  state.reset();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // NetInternalsTest
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 222b4d90..f385536 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1173,24 +1173,24 @@
                  weak_factory_.GetWeakPtr(), callback_id, printer_name));
 }
 
-void PrintPreviewHandler::OnSigninComplete() {
-  if (print_preview_ui())
-    print_preview_ui()->OnReloadPrintersList();
+void PrintPreviewHandler::OnSigninComplete(const std::string& callback_id) {
+  ResolveJavascriptCallback(base::Value(callback_id), base::Value());
 }
 
 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
+  std::string callback_id;
   bool add_account = false;
-  bool success = args->GetBoolean(0, &add_account);
-  DCHECK(success);
+  CHECK(args->GetString(0, &callback_id));
+  CHECK(!callback_id.empty());
+  CHECK(args->GetBoolean(1, &add_account));
 
   Profile* profile = Profile::FromBrowserContext(
       preview_web_contents()->GetBrowserContext());
   chrome::ScopedTabbedBrowserDisplayer displayer(profile);
   print_dialog_cloud::CreateCloudPrintSigninTab(
-      displayer.browser(),
-      add_account,
+      displayer.browser(), add_account,
       base::Bind(&PrintPreviewHandler::OnSigninComplete,
-                 weak_factory_.GetWeakPtr()));
+                 weak_factory_.GetWeakPtr(), callback_id));
 }
 
 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
@@ -1460,7 +1460,7 @@
 void PrintPreviewHandler::OnAddAccountToCookieCompleted(
     const std::string& account_id,
     const GoogleServiceAuthError& error) {
-  OnSigninComplete();
+  FireWebUIListener("reload-printer-list");
 }
 
 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename,
@@ -1557,6 +1557,34 @@
   preview_callbacks_.pop();
 }
 
+void PrintPreviewHandler::SendPrintPresetOptions(bool disable_scaling,
+                                                 int copies,
+                                                 int duplex) {
+  FireWebUIListener("print-preset-options", base::Value(disable_scaling),
+                    base::Value(copies), base::Value(duplex));
+}
+
+void PrintPreviewHandler::SendPageCountReady(int page_count,
+                                             int request_id,
+                                             int fit_to_page_scaling) {
+  FireWebUIListener("page-count-ready", base::Value(page_count),
+                    base::Value(request_id), base::Value(fit_to_page_scaling));
+}
+
+void PrintPreviewHandler::SendPageLayoutReady(
+    const base::DictionaryValue& layout,
+    bool has_custom_page_size_style) {
+  FireWebUIListener("page-layout-ready", layout,
+                    base::Value(has_custom_page_size_style));
+}
+
+void PrintPreviewHandler::SendPagePreviewReady(int page_index,
+                                               int preview_uid,
+                                               int preview_response_id) {
+  FireWebUIListener("page-preview-ready", base::Value(page_index),
+                    base::Value(preview_uid), base::Value(preview_response_id));
+}
+
 void PrintPreviewHandler::OnPrintPreviewCancelled() {
   CHECK(!preview_callbacks_.empty());
   RejectJavascriptCallback(base::Value(preview_callbacks_.front()),
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 34725e3..5b55691 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -86,6 +86,23 @@
   // Called when print preview is ready.
   void OnPrintPreviewReady(int preview_uid, int request_id);
 
+  // Send the print preset options from the document.
+  void SendPrintPresetOptions(bool disable_scaling, int copies, int duplex);
+
+  // Send the print preview page count and fit to page scaling
+  void SendPageCountReady(int page_count,
+                          int request_id,
+                          int fit_to_page_scaling);
+
+  // Send the default page layout
+  void SendPageLayoutReady(const base::DictionaryValue& layout,
+                           bool has_custom_page_size_style);
+
+  // Notify the WebUI that the page preview is ready.
+  void SendPagePreviewReady(int page_index,
+                            int preview_uid,
+                            int preview_response_id);
+
 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
   // Called when the user press ctrl+shift+p to display the native system
   // dialog.
@@ -187,7 +204,7 @@
 #endif
 
   // Callback for the signin dialog to call once signin is complete.
-  void OnSigninComplete();
+  void OnSigninComplete(const std::string& callback_id);
 
   // Brings up a dialog to allow the user to sign into cloud print.
   // |args| is unused.
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 74220ae..8493e8c 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -559,11 +559,8 @@
   DCHECK_GT(params.page_count, 0);
   if (g_testing_delegate)
     g_testing_delegate->DidGetPreviewPageCount(params.page_count);
-  base::Value count(params.page_count);
-  base::Value request_id(params.preview_request_id);
-  base::Value fit_to_page_scaling(params.fit_to_page_scaling);
-  web_ui()->CallJavascriptFunctionUnsafe("onDidGetPreviewPageCount", count,
-                                         request_id, fit_to_page_scaling);
+  handler_->SendPageCountReady(params.page_count, params.preview_request_id,
+                               params.fit_to_page_scaling);
 }
 
 void PrintPreviewUI::OnDidGetDefaultPageLayout(
@@ -590,22 +587,15 @@
                     printable_area.width());
   layout.SetInteger(printing::kSettingPrintableAreaHeight,
                     printable_area.height());
-
-  base::Value has_page_size_style(has_custom_page_size_style);
-  web_ui()->CallJavascriptFunctionUnsafe("onDidGetDefaultPageLayout", layout,
-                                         has_page_size_style);
+  handler_->SendPageLayoutReady(layout, has_custom_page_size_style);
 }
 
 void PrintPreviewUI::OnDidPreviewPage(int page_number,
                                       int preview_request_id) {
   DCHECK_GE(page_number, 0);
-  base::Value number(page_number);
-  base::Value ui_identifier(id_);
-  base::Value request_id(preview_request_id);
   if (g_testing_delegate)
     g_testing_delegate->DidRenderPreviewPage(web_ui()->GetWebContents());
-  web_ui()->CallJavascriptFunctionUnsafe("onDidPreviewPage", number,
-                                         ui_identifier, request_id);
+  handler_->SendPagePreviewReady(page_number, id_, preview_request_id);
 }
 
 void PrintPreviewUI::OnPreviewDataIsAvailable(int expected_pages_count,
@@ -667,19 +657,10 @@
   delegate->OnDialogCloseFromWebUI();
 }
 
-void PrintPreviewUI::OnReloadPrintersList() {
-  web_ui()->CallJavascriptFunctionUnsafe("reloadPrintersList");
-}
-
 void PrintPreviewUI::OnSetOptionsFromDocument(
     const PrintHostMsg_SetOptionsFromDocument_Params& params) {
-  base::DictionaryValue options;
-  options.SetBoolean(printing::kSettingDisableScaling,
-                     params.is_scaling_disabled);
-  options.SetInteger(printing::kSettingCopies, params.copies);
-  options.SetInteger(printing::kSettingDuplexMode, params.duplex);
-  web_ui()->CallJavascriptFunctionUnsafe("printPresetOptionsFromDocument",
-                                         options);
+  handler_->SendPrintPresetOptions(params.is_scaling_disabled, params.copies,
+                                   params.duplex);
 }
 
 // static
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
index 722c316..856d80d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -135,9 +135,6 @@
   // Closes the print preview dialog.
   void OnClosePrintPreviewDialog();
 
-  // Reload the printers list.
-  void OnReloadPrintersList();
-
   // Notifies the WebUI to set print preset options from source PDF.
   void OnSetOptionsFromDocument(
       const PrintHostMsg_SetOptionsFromDocument_Params& params);
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index f9cf6dd..99ea415 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -180,10 +180,11 @@
   html_source->AddString("hostname", url.host());
 
 #if defined(OS_WIN)
-  if (base::FeatureList::IsEnabled(safe_browsing::kInBrowserCleanerUIFeature) &&
-      safe_browsing::ChromeCleanerController::ShouldShowCleanupInSettingsUI()) {
+  if (base::FeatureList::IsEnabled(safe_browsing::kInBrowserCleanerUIFeature)) {
     AddSettingsPageUIHandler(base::MakeUnique<ChromeCleanupHandler>(profile));
-    html_source->AddBoolean("chromeCleanupEnabled", true);
+
+    if (safe_browsing::ChromeCleanerController::ShouldShowCleanupInSettingsUI())
+      html_source->AddBoolean("chromeCleanupEnabled", true);
   }
 #endif  // defined(OS_WIN)
 
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc
index ce24bb4..a2c1d20 100644
--- a/chrome/browser/win/jumplist.cc
+++ b/chrome/browser/win/jumplist.cc
@@ -841,7 +841,7 @@
   //    closed" category updates for the 1st time after Chrome is launched.
   // 2) The number of icons in |icon_dir| has exceeded the limit.
   if (icon_cur->empty() || FilesExceedLimitInDir(icon_dir, max_items * 2)) {
-    DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit);
+    DeleteDirectoryContent(icon_dir, kFileDeleteLimit);
     icon_cur->clear();
     icon_next->clear();
     // Create new icons only when the directory exists and is empty.
diff --git a/chrome/browser/win/jumplist_file_util.cc b/chrome/browser/win/jumplist_file_util.cc
index 91edc3f..bc150b2 100644
--- a/chrome/browser/win/jumplist_file_util.cc
+++ b/chrome/browser/win/jumplist_file_util.cc
@@ -83,13 +83,6 @@
   ::RemoveDirectory(path.value().c_str());
 }
 
-void DeleteDirectoryContentAndLogRuntime(const base::FilePath& path,
-                                         int max_file_deleted) {
-  SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.DeleteDirectoryContentDuration");
-
-  DeleteDirectoryContent(path, kFileDeleteLimit);
-}
-
 bool FilesExceedLimitInDir(const base::FilePath& path, int max_files) {
   int count = 0;
   base::FileEnumerator file_iter(path, false, base::FileEnumerator::FILES);
diff --git a/chrome/browser/win/jumplist_file_util.h b/chrome/browser/win/jumplist_file_util.h
index 776c6eaf..d4ee4c81 100644
--- a/chrome/browser/win/jumplist_file_util.h
+++ b/chrome/browser/win/jumplist_file_util.h
@@ -34,12 +34,6 @@
 // |path|. If |path| is empty after the call, it is removed.
 void DeleteDirectory(const base::FilePath& path, int max_file_deleted);
 
-// Deletes the content in the folder at |path| and records the runtime to UMA.
-// TODO(chengx): Remove this method and use DeleteDirectoryContent after fixing
-// http://crbug.com/40407.
-void DeleteDirectoryContentAndLogRuntime(const base::FilePath& path,
-                                         int max_file_deleted);
-
 // Returns true if the directory at |path| has more than |max_files| files.
 // Sub-directories are not taken into account here.
 bool FilesExceedLimitInDir(const base::FilePath& path, int max_files);
diff --git a/chrome/common/common_param_traits_macros.h b/chrome/common/common_param_traits_macros.h
index 37ccd810..f6b91cc 100644
--- a/chrome/common/common_param_traits_macros.h
+++ b/chrome/common/common_param_traits_macros.h
@@ -11,7 +11,6 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "ipc/ipc_message_macros.h"
 
-IPC_ENUM_TRAITS_MAX_VALUE(ContentSettingsType,
-                          CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE - 1)
+IPC_ENUM_TRAITS_MAX_VALUE(ContentSettingsType, CONTENT_SETTINGS_NUM_TYPES - 1)
 
 #endif  // CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm
index f41238b..e8a4b4df 100644
--- a/chrome/common/service_process_util_mac.mm
+++ b/chrome/common/service_process_util_mac.mm
@@ -29,14 +29,6 @@
 #include "components/version_info/version_info.h"
 #include "mojo/edk/embedder/named_platform_handle_utils.h"
 
-@interface NSFileManager (YosemiteSDK)
-- (BOOL)getRelationship:(NSURLRelationship*)outRelationship
-            ofDirectory:(NSSearchPathDirectory)directory
-               inDomain:(NSSearchPathDomainMask)domainMask
-            toItemAtURL:(NSURL*)url
-                  error:(NSError**)error;
-@end
-
 using ::base::FilePathWatcher;
 
 namespace {
@@ -363,11 +355,7 @@
     // 10.8, but didn't add getRelationship:... until 10.10.  So fall back to
     // the deprecated function while running on 10.9 (and delete the else block
     // when Chromium requires OS X 10.10+).
-    if ([file_manager respondsToSelector:@selector(getRelationship:
-                                                       ofDirectory:
-                                                          inDomain:
-                                                       toItemAtURL:
-                                                             error:)]) {
+    if (@available(macOS 10.10, *)) {
       NSURLRelationship relationship;
       if ([file_manager getRelationship:&relationship
                             ofDirectory:NSTrashDirectory
diff --git a/chrome/installer/zucchini/OWNERS b/chrome/installer/zucchini/OWNERS
index 8a3e7793..e044f5ee 100644
--- a/chrome/installer/zucchini/OWNERS
+++ b/chrome/installer/zucchini/OWNERS
@@ -1,5 +1,4 @@
 huangs@chromium.org
-etiennep@chromium.org
 wfh@chromium.org
 
 # COMPONENT: Internals>Installer>Diff
diff --git a/chrome/renderer/extensions/app_hooks_delegate.cc b/chrome/renderer/extensions/app_hooks_delegate.cc
index d66ccde..4abb147 100644
--- a/chrome/renderer/extensions/app_hooks_delegate.cc
+++ b/chrome/renderer/extensions/app_hooks_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/renderer/extensions/app_hooks_delegate.h"
 
+#include "extensions/renderer/api_activity_logger.h"
 #include "extensions/renderer/bindings/api_request_handler.h"
 #include "extensions/renderer/bindings/api_signature.h"
 #include "extensions/renderer/script_context_set.h"
@@ -17,11 +18,15 @@
     v8::Local<v8::String> property,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   v8::HandleScope handle_scope(info.GetIsolate());
+  v8::Local<v8::Context> context = info.Holder()->CreationContext();
   ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(info.Holder()->CreationContext());
+      ScriptContextSet::GetContextByV8Context(context);
   DCHECK(script_context);
   auto* core =
       static_cast<AppBindingsCore*>(info.Data().As<v8::External>()->Value());
+  // Since this is more-or-less an API, log it as an API call.
+  APIActivityLogger::LogAPICall(context, "app.getIsInstalled",
+                                std::vector<v8::Local<v8::Value>>());
   info.GetReturnValue().Set(core->GetIsInstalled(script_context));
 }
 
diff --git a/chrome/renderer/safe_browsing/DEPS b/chrome/renderer/safe_browsing/DEPS
index e581dd3..4db2367 100644
--- a/chrome/renderer/safe_browsing/DEPS
+++ b/chrome/renderer/safe_browsing/DEPS
@@ -2,6 +2,7 @@
   "+components/safe_browsing/common",
   "+components/safe_browsing/csd.pb.h",
   "+components/safe_browsing/renderer",
+  "+components/safe_browsing/features.h",
   "+third_party/smhasher",
 ]
 
diff --git a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
index b537f33..53f6814 100644
--- a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
+++ b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
@@ -5,12 +5,12 @@
 #include "components/safe_browsing/renderer/threat_dom_details.h"
 
 #include <memory>
-
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "components/safe_browsing/common/safebrowsing_messages.h"
+#include "components/safe_browsing/features.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/renderer/render_view.h"
 #include "net/base/escape.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 388a01c..d31d2edf 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1720,7 +1720,6 @@
       "$root_out_dir/remoting/unittests/",
       "$root_out_dir/test_case.html",
       "$root_out_dir/test_case.html.mock-http-headers",
-      "$root_out_dir/test_data/",
       "$root_out_dir/test_page.css",
       "$root_out_dir/test_page.css.mock-http-headers",
       "$root_out_dir/test_url_loader_data/",
@@ -3470,6 +3469,7 @@
     "//components/ntp_snippets:test_support",
     "//components/os_crypt:test_support",
     "//components/resources",
+    "//components/safe_browsing:features",
     "//components/safe_browsing_db",
     "//components/safe_browsing_db:test_database_manager",
     "//components/safe_json:test_support",
diff --git a/chrome/test/base/javascript_browser_test.cc b/chrome/test/base/javascript_browser_test.cc
index e1f1829e..1c0464e8 100644
--- a/chrome/test/base/javascript_browser_test.cc
+++ b/chrome/test/base/javascript_browser_test.cc
@@ -49,10 +49,20 @@
   test_data_directory = test_data_directory.Append(kWebUITestFolder);
   library_search_paths_.push_back(test_data_directory);
 
+// When the sanitizers (ASAN/MSAN/TSAN) are enabled, the WebUI tests
+// which use this generated directory are disabled in the build.
+// However, the generated directory is there if NaCl is enabled --
+// though it's usually disabled on the bots when the sanitizers are
+// enabled. Also, it seems some ChromeOS-specific tests use the
+// js2gtest GN template.
+#if (!defined(MEMORY_SANITIZER) && !defined(ADDRESS_SANITIZER) && \
+     !defined(LEAK_SANITIZER) && !defined(SYZYASAN)) ||           \
+    !defined(DISABLE_NACL) || defined(OS_CHROMEOS)
   base::FilePath gen_test_data_directory;
   ASSERT_TRUE(
       PathService::Get(chrome::DIR_GEN_TEST_DATA, &gen_test_data_directory));
   library_search_paths_.push_back(gen_test_data_directory);
+#endif
 
   base::FilePath source_root_directory;
   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &source_root_directory));
diff --git a/chrome/test/base/mojo_test_connector.cc b/chrome/test/base/mojo_test_connector.cc
index e76c270..d071475 100644
--- a/chrome/test/base/mojo_test_connector.cc
+++ b/chrome/test/base/mojo_test_connector.cc
@@ -47,14 +47,18 @@
   MojoTestState(MojoTestConnector* connector,
                 base::CommandLine* command_line,
                 base::TestLauncher::LaunchOptions* test_launch_options,
-                const std::string& mus_config_switch)
+                MojoTestConnector::Config config)
       : connector_(connector),
         background_service_manager_(nullptr),
         platform_channel_(base::MakeUnique<mojo::edk::PlatformChannelPair>()),
         main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+        config_(config),
         weak_factory_(this) {
     command_line->AppendSwitch(MojoTestConnector::kTestSwitch);
-    command_line->AppendSwitchASCII(switches::kMusConfig, mus_config_switch);
+    command_line->AppendSwitchASCII(switches::kMusConfig,
+                                    config_ == MojoTestConnector::Config::MASH
+                                        ? switches::kMash
+                                        : switches::kMus);
 
     platform_channel_->PrepareToPassClientHandleToChildProcess(
         command_line, &handle_passing_info_);
@@ -115,9 +119,11 @@
     pid_receiver_->SetPID(pid);
     pid_receiver_.reset();
 
-    background_service_manager_->StartService(
-        service_manager::Identity(mash::session::mojom::kServiceName,
-                                  service_manager::mojom::kRootUserID));
+    if (config_ == MojoTestConnector::Config::MASH) {
+      background_service_manager_->StartService(
+          service_manager::Identity(mash::session::mojom::kServiceName,
+                                    service_manager::mojom::kRootUserID));
+    }
   }
 
   mojo::edk::OutgoingBrokerClientInvitation broker_client_invitation_;
@@ -138,6 +144,8 @@
   service_manager::mojom::PIDReceiverPtr pid_receiver_;
   const scoped_refptr<base::TaskRunner> main_task_runner_;
 
+  const MojoTestConnector::Config config_;
+
   base::WeakPtrFactory<MojoTestState> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoTestState);
@@ -260,10 +268,8 @@
 std::unique_ptr<content::TestState> MojoTestConnector::PrepareForTest(
     base::CommandLine* command_line,
     base::TestLauncher::LaunchOptions* test_launch_options) {
-  return base::MakeUnique<MojoTestState>(
-      this, command_line, test_launch_options,
-      config_ == MojoTestConnector::Config::MASH ? switches::kMash
-                                                 : switches::kMus);
+  return base::MakeUnique<MojoTestState>(this, command_line,
+                                         test_launch_options, config_);
 }
 
 void MojoTestConnector::StartService(const std::string& service_name) {
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py b/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
index 16a36ca..d4ed0cea 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
+++ b/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
@@ -15,9 +15,7 @@
 def GetPathsToPrepend(input_api):
   web_dev_style_path = input_api.os_path.join(
       input_api.change.RepositoryRoot(),
-      'chrome',
-      'browser',
-      'resources')
+      'tools')
   return [input_api.PresubmitLocalPath(), web_dev_style_path]
 
 def RunWithPrependedPath(prepended_path, fn, *args):
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
index fb726a48..d4ea2bc 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
@@ -39,9 +39,11 @@
                                'app_bindings', function response() { });
   },
   expected_activity: [
-    'app.GetDetails',
-    'app.GetIsInstalled',
-    'app.getInstallState'
+    // These API calls show up differently depending on whether native bindings
+    // are enabled.
+    /app\.[gG]etDetails/,
+    /app\.[gG]etIsInstalled/,
+    /app\.(getI|i)nstallState/,
   ]
 });
 testCases.push({
@@ -482,7 +484,11 @@
         expectedCall = testCase.expected_activity[callIndx];
       }
       console.log('Logged:' + apiCall + ' Expected:' + expectedCall);
-      chrome.test.assertEq(expectedCall, apiCall);
+      // Allow either a RegExp or a strict string comparison.
+      if (expectedCall instanceof RegExp)
+        chrome.test.assertTrue(expectedCall.test(apiCall));
+      else
+        chrome.test.assertEq(expectedCall, apiCall);
 
       // Check that no real URLs are logged in incognito-mode tests.  Ignore
       // the initial call to windows.create opening the tab.
diff --git a/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
index 57475d88..1307f405 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/interstitial_teardown/embedder.js
@@ -2,9 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+var webview;
+
+window.createGuest = function() {
+  webview = document.createElement('webview');
+  webview.src = 'about:blank';
+  document.body.appendChild(webview);
+  chrome.test.sendMessage('GuestAddedToDom');
+}
+
 window.loadGuest = function(port) {
   window.console.log('embedder.loadGuest: ' + port);
-  var webview = document.createElement('webview');
 
   // This page is not loaded, we just need a https URL.
   var guestSrcHTTPS = 'https://localhost:' + port +
@@ -16,8 +24,7 @@
   webview.style.left = '0px';
   webview.style.top = '0px';
 
-  document.body.appendChild(webview);
-  chrome.test.sendMessage('GuestAddedToDom');
+  chrome.test.sendMessage('GuestLoaded');
 };
 
 window.onload = function() {
diff --git a/chrome/test/data/geolocation/basic_geolocation.js b/chrome/test/data/geolocation/basic_geolocation.js
index 19c5d305..bc1c3354 100644
--- a/chrome/test/data/geolocation/basic_geolocation.js
+++ b/chrome/test/data/geolocation/basic_geolocation.js
@@ -52,10 +52,6 @@
             {maximumAge:600000, timeout:100000, enableHighAccuracy:true});
   sendString('requested');
 }
-function checkIfGeopositionUpdated() {
-  if (position_updated)
-    sendString('geoposition-updated');
-}
 function geoGetLastPositionLatitude() {
   return "" + last_position.coords.latitude;
 }
@@ -67,4 +63,4 @@
 }
 function geoAccessNavigatorGeolocation() {
   return "" + typeof(navigator.geolocation);
-}
\ No newline at end of file
+}
diff --git a/chrome/test/data/geolocation/two_watches.html b/chrome/test/data/geolocation/two_watches.html
index ca2b0ab..2c723b9 100644
--- a/chrome/test/data/geolocation/two_watches.html
+++ b/chrome/test/data/geolocation/two_watches.html
@@ -32,11 +32,6 @@
       sendString('request-callback-success');
     }
 
-    function checkIfGeopositionUpdated() {
-      if (position_updated)
-        sendString('geoposition-updated');
-    }
-
     // This will be triggered twice:
     //  1. When the permission request is approved, it will receive an initial
     //     value. At this point, the callback does not directly notify success
diff --git a/chrome/test/data/webui/net_internals/log_util.js b/chrome/test/data/webui/net_internals/log_util.js
index b43fadf..b8e72f3 100644
--- a/chrome/test/data/webui/net_internals/log_util.js
+++ b/chrome/test/data/webui/net_internals/log_util.js
@@ -93,12 +93,11 @@
 };
 
 /**
-  * A Task that creates a log dump in the browser process via
-  * WriteToFileNetLogObserver, waits to receive it via IPC, and and then loads
-  * it as a string.
+  * A Task that creates a log dump in the browser process, waits to receive it
+  * via IPC, and and then loads it as a string.
   * @param {integer} truncate The number of bytes to truncate from the end of
   *     the string, if any, to simulate a truncated log due to crash, or
-  *     quitting without properly shutting down a WriteToFileNetLogObserver.
+  *     quitting without properly shutting down the log writer.
   * @extends {NetInternalsTest.Task}
   */
 function GetNetLogFileContentsAndLoadLogTask(truncate) {
@@ -178,7 +177,7 @@
 
 /**
  * Checks the visibility of each view after loading a log dump created by the
- * WriteToFileNetLogObserver. Also checks that the BrowserBridge is disabled.
+ * browser. Also checks that the BrowserBridge is disabled.
  */
 function checkViewsAfterNetLogFileLoaded() {
   expectTrue(g_browser.isDisabled());
@@ -235,9 +234,8 @@
 });
 
 /**
- * Exports a log dump by using a WriteToFileNetLogObserver and attempts to load
- * it from a string.  The string is passed to Javascript via an IPC rather than
- * drag and drop.
+ * Attempts to load a NetLog created by the browser. The log contents are
+ * passed to Javascript via an IPC rather than drag and drop.
  */
 TEST_F('NetInternalsTest',
     'netInternalsLogUtilImportNetLogFile',
diff --git a/chrome/test/data/webui/print_preview/native_layer_stub.js b/chrome/test/data/webui/print_preview/native_layer_stub.js
index e95b708..f312268 100644
--- a/chrome/test/data/webui/print_preview/native_layer_stub.js
+++ b/chrome/test/data/webui/print_preview/native_layer_stub.js
@@ -21,12 +21,6 @@
       ]);
 
     /**
-     * @private {!cr.EventTarget} The event target used for dispatching and
-     *     receiving events.
-     */
-    this.eventTarget_ = new cr.EventTarget();
-
-    /**
      * @private {!print_preview.NativeInitialSettings} The initial settings
      *     to be used for the response to a |getInitialSettings| call.
      */
@@ -95,12 +89,31 @@
         generateDraft: generateDraft,
         requestId: requestId,
       });
-      var rejectString = print_preview.PreviewArea.EventType.SETTINGS_INVALID;
-      rejectString = rejectString.substring(
-          rejectString.lastIndexOf(".") + 1, rejectString.length);
-      return destination.id == this.badPrinterId_ ?
-          Promise.reject(rejectString) :
-          Promise.resolve(requestId);
+      if (destination.id == this.badPrinterId_) {
+        var rejectString = print_preview.PreviewArea.EventType.SETTINGS_INVALID;
+        rejectString = rejectString.substring(
+            rejectString.lastIndexOf('.') + 1, rejectString.length);
+        return Promise.reject(rejectString);
+      }
+      var pageRanges = printTicketStore.pageRange.getDocumentPageRanges();
+      if (pageRanges.length == 0) {  // assume full length document, 1 page.
+        cr.webUIListenerCallback('page-count-ready', 1, requestId, 100);
+        cr.webUIListenerCallback('page-preview-ready', 0, 0, requestId);
+      } else {
+        var pages = pageRanges.reduce(function(soFar, range) {
+          for (var page = range.from; page <= range.to; page++) {
+            soFar.push(page);
+          }
+          return soFar;
+        }, []);
+        cr.webUIListenerCallback(
+            'page-count-ready', pages.length, requestId, 100);
+        pages.forEach(function(page) {
+          cr.webUIListenerCallback(
+              'page-preview-ready', page - 1, 0, requestId);
+        });
+      }
+      return Promise.resolve(requestId);
     },
 
     /** @override */
@@ -136,17 +149,8 @@
     },
 
     /** Stubs for |print_preview.NativeLayer| methods that call C++ handlers. */
-    previewReadyForTest: function() {},
     startHideDialog: function () {},
 
-    /** @return {!cr.EventTarget} The native layer event target. */
-    getEventTarget: function() { return this.eventTarget_; },
-
-    /** @param {!cr.EventTarget} eventTarget The event target to use. */
-    setEventTarget: function(eventTarget) {
-      this.eventTarget_ = eventTarget;
-    },
-
     /**
      * @param {!print_preview.NativeInitialSettings} settings The settings
      *     to return as a response to |getInitialSettings|.
diff --git a/chrome/test/data/webui/print_preview/plugin_stub.js b/chrome/test/data/webui/print_preview/plugin_stub.js
index 1c141b9..6e3d339 100644
--- a/chrome/test/data/webui/print_preview/plugin_stub.js
+++ b/chrome/test/data/webui/print_preview/plugin_stub.js
@@ -17,15 +17,6 @@
        */
       this.loadCallback_ = null;
 
-      /** @private {!EventTracker} The plugin stub's event tracker. */
-      this.tracker_ = new EventTracker();
-
-      // Call documentLoadComplete as soon as the preview area starts the
-      // preview.
-      this.tracker_.add(
-          area,
-          print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
-          this.documentLoadComplete.bind(this));
     }
 
     /**
@@ -36,11 +27,6 @@
       this.loadCallback_ = callback;
     }
 
-    documentLoadComplete() {
-      if (this.loadCallback_)
-        this.loadCallback_();
-    }
-
     /**
      * Stubbed out since some tests result in a call.
      * @param {string} url The url to initialize the plugin to.
@@ -49,6 +35,17 @@
      * @param {boolean} modifiable Whether the source document is modifiable.
      */
     resetPrintPreviewMode(url, color, pages, modifiable) {}
+
+    /**
+     * Called when the preview area wants the plugin to load a preview page.
+     * Immediately calls loadCallback_().
+     * @param {string} url The preview URL
+     * @param {number} index The index of the page number to load.
+     */
+    loadPreviewPage(url, index) {
+      if (this.loadCallback_)
+        this.loadCallback_();
+    }
   }
 
   return {PDFPluginStub: PDFPluginStub};
diff --git a/chrome/test/data/webui/print_preview/print_preview_destination_search_test.js b/chrome/test/data/webui/print_preview/print_preview_destination_search_test.js
index e5ea6e4..8518af1 100644
--- a/chrome/test/data/webui/print_preview/print_preview_destination_search_test.js
+++ b/chrome/test/data/webui/print_preview/print_preview_destination_search_test.js
@@ -124,17 +124,11 @@
     };
 
     setup(function() {
-      Mock4JS.clearMocksToVerify();
       nativeLayer_ = new print_preview.NativeLayerStub();
-      var nativeLayerEventTarget = mock(cr.EventTarget);
-      nativeLayer_.setEventTarget(nativeLayerEventTarget.proxy());
-      nativeLayerEventTarget.expects(atLeastOnce())
-          .addEventListener(ANYTHING, ANYTHING, ANYTHING);
-
       invitationStore_ = new print_preview.InvitationStore();
       destinationStore_ = new print_preview.DestinationStore(
           nativeLayer_, new print_preview.UserInfo(),
-          new print_preview.AppState());
+          new print_preview.AppState(), new WebUIListenerTracker());
       userInfo_ = new print_preview.UserInfo();
 
       destinationSearch_ = new print_preview.DestinationSearch(
@@ -142,10 +136,6 @@
       destinationSearch_.decorate($('destination-search'));
     });
 
-    teardown(function() {
-      Mock4JS.verifyAllMocks();
-    });
-
     test('ResolutionFails', function() {
       var destId = "001122DEADBEEF";
       if (cr.isChromeOS) {
diff --git a/chrome/test/data/webui/print_preview/print_preview_tests.js b/chrome/test/data/webui/print_preview/print_preview_tests.js
index b38e99f6..39e5c883 100644
--- a/chrome/test/data/webui/print_preview/print_preview_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_tests.js
@@ -693,21 +693,12 @@
       return setupSettingsAndDestinationsWithCapabilities().then(function() {
         // Indicate that the number of copies print preset is set for source
         // PDF.
-        var printPresetOptions = {
-          disableScaling: true,
-          copies: 2
-        };
-        var printPresetOptionsEvent = new Event(
-            print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS);
-        printPresetOptionsEvent.optionsFromDocument = printPresetOptions;
-        nativeLayer.getEventTarget().
-            dispatchEvent(printPresetOptionsEvent);
-
+        var copies = 2;
+        cr.webUIListenerCallback('print-preset-options', true, copies);
         checkSectionVisible($('copies-settings'), true);
         expectEquals(
-            printPresetOptions.copies,
-            parseInt($('copies-settings').
-                querySelector('.user-value').value));
+            copies,
+            parseInt($('copies-settings').querySelector('.user-value').value));
 
         return whenAnimationDone('other-options-collapsible');
       });
@@ -720,15 +711,7 @@
       return setupSettingsAndDestinationsWithCapabilities().then(function() {
         // Indicate that the duplex print preset is set to 'long edge' for
         // source PDF.
-        var printPresetOptions = {
-          duplex: 1
-        };
-        var printPresetOptionsEvent = new Event(
-            print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS);
-        printPresetOptionsEvent.optionsFromDocument = printPresetOptions;
-        nativeLayer.getEventTarget().
-            dispatchEvent(printPresetOptionsEvent);
-
+        cr.webUIListenerCallback('print-preset-options', false, 1, 1);
         var otherOptions = $('other-options-settings');
         checkSectionVisible(otherOptions, true);
         var duplexContainer =
diff --git a/chrome/test/data/webui/settings/about_page_tests.js b/chrome/test/data/webui/settings/about_page_tests.js
index d2d69132..aac3339 100644
--- a/chrome/test/data/webui/settings/about_page_tests.js
+++ b/chrome/test/data/webui/settings/about_page_tests.js
@@ -201,7 +201,7 @@
         lifetimeBrowserProxy.reset();
         PolymerTest.clearBody();
         page = document.createElement('settings-about-page');
-        settings.navigateTo(settings.Route.ABOUT);
+        settings.navigateTo(settings.routes.ABOUT);
         document.body.appendChild(page);
         if (!cr.isChromeOS) {
           return aboutBrowserProxy.whenCalled('refreshUpdateStatus');
diff --git a/chrome/test/data/webui/settings/android_apps_page_test.js b/chrome/test/data/webui/settings/android_apps_page_test.js
index 84dab47..05ba9a3 100644
--- a/chrome/test/data/webui/settings/android_apps_page_test.js
+++ b/chrome/test/data/webui/settings/android_apps_page_test.js
@@ -76,7 +76,7 @@
       androidAppsPage.havePlayStoreApp = true;
       androidAppsPage.prefs = {arc: {enabled: {value: true}}};
       setAndroidAppsState(true, false);
-      settings.navigateTo(settings.Route.ANDROID_APPS);
+      settings.navigateTo(settings.routes.ANDROID_APPS);
       MockInteractions.tap(androidAppsPage.$$('#android-apps'));
       Polymer.dom.flush();
       subpage = androidAppsPage.$$('settings-android-apps-subpage');
@@ -126,12 +126,11 @@
     });
 
     test('HideOnDisable', function() {
-      assertEquals(settings.getCurrentRoute(),
-                   settings.Route.ANDROID_APPS_DETAILS);
+      assertEquals(
+          settings.getCurrentRoute(), settings.routes.ANDROID_APPS_DETAILS);
       setAndroidAppsState(false, false);
       return whenPopState().then(function() {
-        assertEquals(settings.getCurrentRoute(),
-            settings.Route.ANDROID_APPS);
+        assertEquals(settings.getCurrentRoute(), settings.routes.ANDROID_APPS);
       });
     });
   });
diff --git a/chrome/test/data/webui/settings/basic_page_browsertest.js b/chrome/test/data/webui/settings/basic_page_browsertest.js
index 609c5ca..458cd009 100644
--- a/chrome/test/data/webui/settings/basic_page_browsertest.js
+++ b/chrome/test/data/webui/settings/basic_page_browsertest.js
@@ -96,7 +96,7 @@
     test('scroll to section', function() {
       var page = self.basicPage;
       // Setting the page and section will cause a scrollToSection_.
-      settings.navigateTo(settings.Route.ON_STARTUP);
+      settings.navigateTo(settings.routes.ON_STARTUP);
 
       return new Promise(function(resolve, reject) {
         // This test checks for a regression that occurred with scrollToSection_
@@ -134,14 +134,15 @@
       var searchManager = new TestSearchManager();
       settings.setSearchManagerForTesting(searchManager);
 
-      settings.navigateTo(settings.Route.BASIC,
-                          new URLSearchParams(`search=foobar`),
-                          /* removeSearch */ false);
+      settings.navigateTo(
+          settings.routes.BASIC, new URLSearchParams(`search=foobar`),
+          /* removeSearch */ false);
       return searchManager.whenCalled('search').then(function() {
         return new Promise(function(resolve) {
-          settings.navigateTo(settings.Route.ON_STARTUP,
-                              /* dynamicParams */ null,
-                              /* removeSearch */ true);
+          settings.navigateTo(
+              settings.routes.ON_STARTUP,
+              /* dynamicParams */ null,
+              /* removeSearch */ true);
 
           assertTrue(!!page);
 
@@ -161,10 +162,10 @@
       // Set the viewport small to force the scrollbar to appear on ABOUT.
       Polymer.dom().querySelector('settings-ui').style.height = '200px';
 
-      settings.navigateTo(settings.Route.ON_STARTUP);
+      settings.navigateTo(settings.routes.ON_STARTUP);
       assertNotEquals(0, page.scroller.scrollTop);
 
-      settings.navigateTo(settings.Route.ABOUT);
+      settings.navigateTo(settings.routes.ABOUT);
       assertEquals(0, page.scroller.scrollTop);
     });
   });
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 3e7c3660..a8a0515 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1434,7 +1434,7 @@
 TEST_F('CrSettingsNonExistentRouteTest', 'MAYBE_NonExistentRoute', function() {
   suite('NonExistentRoutes', function() {
     test('redirect to basic', function() {
-      assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
+      assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
       assertEquals('/', location.pathname);
     });
   });
@@ -1460,22 +1460,22 @@
 TEST_F('CrSettingsRouteDynamicParametersTest', 'All', function() {
   suite('DynamicParameters', function() {
     test('get parameters from URL and navigation', function(done) {
-      assertEquals(settings.Route.SEARCH, settings.getCurrentRoute());
+      assertEquals(settings.routes.SEARCH, settings.getCurrentRoute());
       assertEquals('a/b', settings.getQueryParameters().get('guid'));
       assertEquals('42', settings.getQueryParameters().get('foo'));
 
       var params = new URLSearchParams();
       params.set('bar', 'b=z');
       params.set('biz', '3');
-      settings.navigateTo(settings.Route.SEARCH_ENGINES, params);
-      assertEquals(settings.Route.SEARCH_ENGINES, settings.getCurrentRoute());
+      settings.navigateTo(settings.routes.SEARCH_ENGINES, params);
+      assertEquals(settings.routes.SEARCH_ENGINES, settings.getCurrentRoute());
       assertEquals('b=z', settings.getQueryParameters().get('bar'));
       assertEquals('3', settings.getQueryParameters().get('biz'));
       assertEquals('?bar=b%3Dz&biz=3', window.location.search);
 
       window.addEventListener('popstate', function(event) {
         assertEquals('/search', settings.getCurrentRoute().path);
-        assertEquals(settings.Route.SEARCH, settings.getCurrentRoute());
+        assertEquals(settings.routes.SEARCH, settings.getCurrentRoute());
         assertEquals('a/b', settings.getQueryParameters().get('guid'));
         assertEquals('42', settings.getQueryParameters().get('foo'));
         done();
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js
index c818b96..7f41ae54 100644
--- a/chrome/test/data/webui/settings/device_page_tests.js
+++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -246,7 +246,7 @@
       settings.display.systemDisplayApi = fakeSystemDisplay;
 
       PolymerTest.clearBody();
-      settings.navigateTo(settings.Route.BASIC);
+      settings.navigateTo(settings.routes.BASIC);
 
       devicePage = document.createElement('settings-device-page');
       devicePage.prefs = getFakePrefs();
@@ -344,21 +344,21 @@
       var pointersPage;
 
       setup(function() {
-        return showAndGetDeviceSubpage(
-            'pointers', settings.Route.POINTERS).then(function(page) {
+        return showAndGetDeviceSubpage('pointers', settings.routes.POINTERS)
+            .then(function(page) {
               pointersPage = page;
             });
       });
 
       test('subpage responds to pointer attach/detach', function() {
-        assertEquals(settings.Route.POINTERS, settings.getCurrentRoute());
+        assertEquals(settings.routes.POINTERS, settings.getCurrentRoute());
         assertLT(0, pointersPage.$$('#mouse').offsetHeight);
         assertLT(0, pointersPage.$$('#touchpad').offsetHeight);
         assertLT(0, pointersPage.$$('#mouse h2').offsetHeight);
         assertLT(0, pointersPage.$$('#touchpad h2').offsetHeight);
 
         cr.webUIListenerCallback('has-touchpad-changed', false);
-        assertEquals(settings.Route.POINTERS, settings.getCurrentRoute());
+        assertEquals(settings.routes.POINTERS, settings.getCurrentRoute());
         assertLT(0, pointersPage.$$('#mouse').offsetHeight);
         assertEquals(0, pointersPage.$$('#touchpad').offsetHeight);
         assertEquals(0, pointersPage.$$('#mouse h2').offsetHeight);
@@ -366,30 +366,34 @@
 
         // Wait for the transition back to the main page.
         return new Promise(function(resolve, reject) {
-          devicePage.$$('#pages').addEventListener(
-              'neon-animation-finish', resolve);
+                 devicePage.$$('#pages').addEventListener(
+                     'neon-animation-finish', resolve);
 
-          cr.webUIListenerCallback('has-mouse-changed', false);
-        }).then(function() {
-          assertEquals(settings.Route.DEVICE, settings.getCurrentRoute());
-          assertEquals(0, devicePage.$$('#main #pointersRow').offsetHeight);
+                 cr.webUIListenerCallback('has-mouse-changed', false);
+               })
+            .then(function() {
+              assertEquals(settings.routes.DEVICE, settings.getCurrentRoute());
+              assertEquals(0, devicePage.$$('#main #pointersRow').offsetHeight);
 
-          cr.webUIListenerCallback('has-touchpad-changed', true);
-          assertLT(0, devicePage.$$('#main #pointersRow').offsetHeight);
-          return showAndGetDeviceSubpage('pointers', settings.Route.POINTERS);
-        }).then(function(page) {
-          assertEquals(0, pointersPage.$$('#mouse').offsetHeight);
-          assertLT(0, pointersPage.$$('#touchpad').offsetHeight);
-          assertEquals(0, pointersPage.$$('#mouse h2').offsetHeight);
-          assertEquals(0, pointersPage.$$('#touchpad h2').offsetHeight);
+              cr.webUIListenerCallback('has-touchpad-changed', true);
+              assertLT(0, devicePage.$$('#main #pointersRow').offsetHeight);
+              return showAndGetDeviceSubpage(
+                  'pointers', settings.routes.POINTERS);
+            })
+            .then(function(page) {
+              assertEquals(0, pointersPage.$$('#mouse').offsetHeight);
+              assertLT(0, pointersPage.$$('#touchpad').offsetHeight);
+              assertEquals(0, pointersPage.$$('#mouse h2').offsetHeight);
+              assertEquals(0, pointersPage.$$('#touchpad h2').offsetHeight);
 
-          cr.webUIListenerCallback('has-mouse-changed', true);
-          assertEquals(settings.Route.POINTERS, settings.getCurrentRoute());
-          assertLT(0, pointersPage.$$('#mouse').offsetHeight);
-          assertLT(0, pointersPage.$$('#touchpad').offsetHeight);
-          assertLT(0, pointersPage.$$('#mouse h2').offsetHeight);
-          assertLT(0, pointersPage.$$('#touchpad h2').offsetHeight);
-        });
+              cr.webUIListenerCallback('has-mouse-changed', true);
+              assertEquals(
+                  settings.routes.POINTERS, settings.getCurrentRoute());
+              assertLT(0, pointersPage.$$('#mouse').offsetHeight);
+              assertLT(0, pointersPage.$$('#touchpad').offsetHeight);
+              assertLT(0, pointersPage.$$('#mouse h2').offsetHeight);
+              assertLT(0, pointersPage.$$('#touchpad h2').offsetHeight);
+            });
       });
 
       test('mouse', function() {
@@ -459,74 +463,77 @@
 
     test(assert(TestNames.Keyboard), function() {
       // Open the keyboard subpage.
-      return showAndGetDeviceSubpage(
-          'keyboard', settings.Route.KEYBOARD).then(function(keyboardPage) {
-        // Initially, the optional keys are hidden.
-        expectFalse(!!keyboardPage.$$('#capsLockKey'));
-        expectFalse(!!keyboardPage.$$('#diamondKey'));
+      return showAndGetDeviceSubpage('keyboard', settings.routes.KEYBOARD)
+          .then(function(keyboardPage) {
+            // Initially, the optional keys are hidden.
+            expectFalse(!!keyboardPage.$$('#capsLockKey'));
+            expectFalse(!!keyboardPage.$$('#diamondKey'));
 
-        // Pretend the diamond key is available.
-        var showCapsLock = false;
-        var showDiamondKey = true;
-        cr.webUIListenerCallback(
-            'show-keys-changed', showCapsLock, showDiamondKey);
-        Polymer.dom.flush();
-        expectFalse(!!keyboardPage.$$('#capsLockKey'));
-        expectTrue(!!keyboardPage.$$('#diamondKey'));
+            // Pretend the diamond key is available.
+            var showCapsLock = false;
+            var showDiamondKey = true;
+            cr.webUIListenerCallback(
+                'show-keys-changed', showCapsLock, showDiamondKey);
+            Polymer.dom.flush();
+            expectFalse(!!keyboardPage.$$('#capsLockKey'));
+            expectTrue(!!keyboardPage.$$('#diamondKey'));
 
-        // Pretend a Caps Lock key is now available.
-        showCapsLock = true;
-        cr.webUIListenerCallback(
-            'show-keys-changed', showCapsLock, showDiamondKey);
-        Polymer.dom.flush();
-        expectTrue(!!keyboardPage.$$('#capsLockKey'));
-        expectTrue(!!keyboardPage.$$('#diamondKey'));
+            // Pretend a Caps Lock key is now available.
+            showCapsLock = true;
+            cr.webUIListenerCallback(
+                'show-keys-changed', showCapsLock, showDiamondKey);
+            Polymer.dom.flush();
+            expectTrue(!!keyboardPage.$$('#capsLockKey'));
+            expectTrue(!!keyboardPage.$$('#diamondKey'));
 
-        var collapse = keyboardPage.$$('iron-collapse');
-        assertTrue(!!collapse);
-        expectTrue(collapse.opened);
+            var collapse = keyboardPage.$$('iron-collapse');
+            assertTrue(!!collapse);
+            expectTrue(collapse.opened);
 
-        expectEquals(500, keyboardPage.$$('#delaySlider').pref.value);
-        expectEquals(500, keyboardPage.$$('#repeatRateSlider').pref.value);
+            expectEquals(500, keyboardPage.$$('#delaySlider').pref.value);
+            expectEquals(500, keyboardPage.$$('#repeatRateSlider').pref.value);
 
-        // Test interaction with the settings-slider's underlying paper-slider.
-        MockInteractions.pressAndReleaseKeyOn(
-            keyboardPage.$$('#delaySlider').$$('#slider'), 37 /* left */);
-        MockInteractions.pressAndReleaseKeyOn(
-            keyboardPage.$$('#repeatRateSlider').$$('#slider'), 39 /* right */);
-        var language = devicePage.prefs.settings.language;
-        expectEquals(1000, language.xkb_auto_repeat_delay_r2.value);
-        expectEquals(300, language.xkb_auto_repeat_interval_r2.value);
+            // Test interaction with the settings-slider's underlying
+            // paper-slider.
+            MockInteractions.pressAndReleaseKeyOn(
+                keyboardPage.$$('#delaySlider').$$('#slider'), 37 /* left */);
+            MockInteractions.pressAndReleaseKeyOn(
+                keyboardPage.$$('#repeatRateSlider').$$('#slider'),
+                39 /* right */);
+            var language = devicePage.prefs.settings.language;
+            expectEquals(1000, language.xkb_auto_repeat_delay_r2.value);
+            expectEquals(300, language.xkb_auto_repeat_interval_r2.value);
 
-        // Test sliders change when prefs change.
-        devicePage.set(
-            'prefs.settings.language.xkb_auto_repeat_delay_r2.value', 1500);
-        expectEquals(1500, keyboardPage.$$('#delaySlider').pref.value);
-        devicePage.set(
-            'prefs.settings.language.xkb_auto_repeat_interval_r2.value',
-            2000);
-        expectEquals(2000, keyboardPage.$$('#repeatRateSlider').pref.value);
+            // Test sliders change when prefs change.
+            devicePage.set(
+                'prefs.settings.language.xkb_auto_repeat_delay_r2.value', 1500);
+            expectEquals(1500, keyboardPage.$$('#delaySlider').pref.value);
+            devicePage.set(
+                'prefs.settings.language.xkb_auto_repeat_interval_r2.value',
+                2000);
+            expectEquals(2000, keyboardPage.$$('#repeatRateSlider').pref.value);
 
-        // Test sliders round to nearest value when prefs change.
-        devicePage.set(
-            'prefs.settings.language.xkb_auto_repeat_delay_r2.value', 600);
-        expectEquals(500, keyboardPage.$$('#delaySlider').pref.value);
-        devicePage.set(
-            'prefs.settings.language.xkb_auto_repeat_interval_r2.value', 45);
-        expectEquals(50, keyboardPage.$$('#repeatRateSlider').pref.value);
+            // Test sliders round to nearest value when prefs change.
+            devicePage.set(
+                'prefs.settings.language.xkb_auto_repeat_delay_r2.value', 600);
+            expectEquals(500, keyboardPage.$$('#delaySlider').pref.value);
+            devicePage.set(
+                'prefs.settings.language.xkb_auto_repeat_interval_r2.value',
+                45);
+            expectEquals(50, keyboardPage.$$('#repeatRateSlider').pref.value);
 
-        devicePage.set(
-            'prefs.settings.language.xkb_auto_repeat_enabled_r2.value',
-            false);
-        expectFalse(collapse.opened);
+            devicePage.set(
+                'prefs.settings.language.xkb_auto_repeat_enabled_r2.value',
+                false);
+            expectFalse(collapse.opened);
 
-        // Test keyboard shortcut overlay button.
-        MockInteractions.tap(keyboardPage.$$('#keyboardOverlay'));
-        expectEquals(
-            1,
-            settings.DevicePageBrowserProxyImpl.getInstance()
-                .keyboardShortcutsOverlayShown_);
-      });
+            // Test keyboard shortcut overlay button.
+            MockInteractions.tap(keyboardPage.$$('#keyboardOverlay'));
+            expectEquals(
+                1,
+                settings.DevicePageBrowserProxyImpl.getInstance()
+                    .keyboardShortcutsOverlayShown_);
+          });
     });
 
     test(assert(TestNames.Display), function() {
@@ -549,100 +556,115 @@
       };
 
       var displayPage;
-      return Promise.all([
-        // Get the display sub-page.
-        showAndGetDeviceSubpage(
-            'display', settings.Route.DISPLAY).then(function(page) {
-          displayPage = page;
-        }),
-        // Wait for the initial call to getInfo.
-        fakeSystemDisplay.getInfoCalled.promise,
-      ]).then(function() {
-        // Add a display.
-        addDisplay(1);
-        fakeSystemDisplay.onDisplayChanged.callListeners();
+      return Promise
+          .all([
+            // Get the display sub-page.
+            showAndGetDeviceSubpage('display', settings.routes.DISPLAY)
+                .then(function(page) {
+                  displayPage = page;
+                }),
+            // Wait for the initial call to getInfo.
+            fakeSystemDisplay.getInfoCalled.promise,
+          ])
+          .then(function() {
+            // Add a display.
+            addDisplay(1);
+            fakeSystemDisplay.onDisplayChanged.callListeners();
 
-        return Promise.all([
-          fakeSystemDisplay.getInfoCalled.promise,
-          fakeSystemDisplay.getLayoutCalled.promise,
-        ]);
-      }).then(function() {
-        // There should be a single display which should be primary and
-        // selected. Mirroring should be disabled.
-        expectEquals(1, displayPage.displays.length);
-        expectEquals(
-            displayPage.displays[0].id, displayPage.selectedDisplay.id);
-        expectEquals(
-            displayPage.displays[0].id, displayPage.primaryDisplayId);
-        expectFalse(displayPage.showMirror_(false, displayPage.displays));
-        expectFalse(displayPage.isMirrored_(displayPage.displays));
+            return Promise.all([
+              fakeSystemDisplay.getInfoCalled.promise,
+              fakeSystemDisplay.getLayoutCalled.promise,
+            ]);
+          })
+          .then(function() {
+            // There should be a single display which should be primary and
+            // selected. Mirroring should be disabled.
+            expectEquals(1, displayPage.displays.length);
+            expectEquals(
+                displayPage.displays[0].id, displayPage.selectedDisplay.id);
+            expectEquals(
+                displayPage.displays[0].id, displayPage.primaryDisplayId);
+            expectFalse(displayPage.showMirror_(false, displayPage.displays));
+            expectFalse(displayPage.isMirrored_(displayPage.displays));
 
-        // Add a second display.
-        addDisplay(2);
-        fakeSystemDisplay.onDisplayChanged.callListeners();
+            // Add a second display.
+            addDisplay(2);
+            fakeSystemDisplay.onDisplayChanged.callListeners();
 
-        return Promise.all([
-          fakeSystemDisplay.getInfoCalled.promise,
-          fakeSystemDisplay.getLayoutCalled.promise,
-          new Promise(function(resolve, reject) { setTimeout(resolve); })
-        ]);
-      }).then(function() {
-        // There should be two displays, the first should be primary and
-        // selected. Mirroring should be enabled but set to false.
-        expectEquals(2, displayPage.displays.length);
-        expectEquals(
-            displayPage.displays[0].id, displayPage.selectedDisplay.id);
-        expectEquals(displayPage.displays[0].id, displayPage.primaryDisplayId);
-        expectTrue(displayPage.showMirror_(false, displayPage.displays));
-        expectFalse(displayPage.isMirrored_(displayPage.displays));
+            return Promise.all([
+              fakeSystemDisplay.getInfoCalled.promise,
+              fakeSystemDisplay.getLayoutCalled.promise,
+              new Promise(function(resolve, reject) {
+                setTimeout(resolve);
+              })
+            ]);
+          })
+          .then(function() {
+            // There should be two displays, the first should be primary and
+            // selected. Mirroring should be enabled but set to false.
+            expectEquals(2, displayPage.displays.length);
+            expectEquals(
+                displayPage.displays[0].id, displayPage.selectedDisplay.id);
+            expectEquals(
+                displayPage.displays[0].id, displayPage.primaryDisplayId);
+            expectTrue(displayPage.showMirror_(false, displayPage.displays));
+            expectFalse(displayPage.isMirrored_(displayPage.displays));
 
-        // Select the second display and make it primary. Also change the
-        // orientation of the second display.
-        var displayLayout = displayPage.$$('#displayLayout');
-        assertTrue(!!displayLayout);
-        var displayDiv = displayLayout.$$('#_fakeDisplayId2');
-        assertTrue(!!displayDiv);
-        MockInteractions.tap(displayDiv);
-        expectEquals(
-            displayPage.displays[1].id, displayPage.selectedDisplay.id);
+            // Select the second display and make it primary. Also change the
+            // orientation of the second display.
+            var displayLayout = displayPage.$$('#displayLayout');
+            assertTrue(!!displayLayout);
+            var displayDiv = displayLayout.$$('#_fakeDisplayId2');
+            assertTrue(!!displayDiv);
+            MockInteractions.tap(displayDiv);
+            expectEquals(
+                displayPage.displays[1].id, displayPage.selectedDisplay.id);
 
-        displayPage.updatePrimaryDisplay_({target: {value: '0'}});
-        displayPage.onOrientationChange_({target: {value: '90'}});
-        fakeSystemDisplay.onDisplayChanged.callListeners();
+            displayPage.updatePrimaryDisplay_({target: {value: '0'}});
+            displayPage.onOrientationChange_({target: {value: '90'}});
+            fakeSystemDisplay.onDisplayChanged.callListeners();
 
-        return Promise.all([
-          fakeSystemDisplay.getInfoCalled.promise,
-          fakeSystemDisplay.getLayoutCalled.promise,
-          new Promise(function(resolve, reject) { setTimeout(resolve); })
-        ]);
-      }).then(function() {
-        // Confirm that the second display is selected, primary, and rotated.
-        expectEquals(2, displayPage.displays.length);
-        expectEquals(
-            displayPage.displays[1].id, displayPage.selectedDisplay.id);
-        expectTrue(displayPage.displays[1].isPrimary);
-        expectEquals(displayPage.displays[1].id, displayPage.primaryDisplayId);
-        expectEquals(90, displayPage.displays[1].rotation);
+            return Promise.all([
+              fakeSystemDisplay.getInfoCalled.promise,
+              fakeSystemDisplay.getLayoutCalled.promise,
+              new Promise(function(resolve, reject) {
+                setTimeout(resolve);
+              })
+            ]);
+          })
+          .then(function() {
+            // Confirm that the second display is selected, primary, and
+            // rotated.
+            expectEquals(2, displayPage.displays.length);
+            expectEquals(
+                displayPage.displays[1].id, displayPage.selectedDisplay.id);
+            expectTrue(displayPage.displays[1].isPrimary);
+            expectEquals(
+                displayPage.displays[1].id, displayPage.primaryDisplayId);
+            expectEquals(90, displayPage.displays[1].rotation);
 
-        // Mirror the displays.
-        displayPage.onMirroredTap_();
-        fakeSystemDisplay.onDisplayChanged.callListeners();
+            // Mirror the displays.
+            displayPage.onMirroredTap_();
+            fakeSystemDisplay.onDisplayChanged.callListeners();
 
-        return Promise.all([
-          fakeSystemDisplay.getInfoCalled.promise,
-          fakeSystemDisplay.getLayoutCalled.promise,
-          new Promise(function(resolve, reject) { setTimeout(resolve); })
-        ]);
-      }).then(function() {
-        // Confirm that there is now only one display and that it is primary
-        // and mirroring is enabled.
-        expectEquals(1, displayPage.displays.length);
-        expectEquals(
-            displayPage.displays[0].id, displayPage.selectedDisplay.id);
-        expectTrue(displayPage.displays[0].isPrimary);
-        expectTrue(displayPage.showMirror_(false, displayPage.displays));
-        expectTrue(displayPage.isMirrored_(displayPage.displays));
-      });
+            return Promise.all([
+              fakeSystemDisplay.getInfoCalled.promise,
+              fakeSystemDisplay.getLayoutCalled.promise,
+              new Promise(function(resolve, reject) {
+                setTimeout(resolve);
+              })
+            ]);
+          })
+          .then(function() {
+            // Confirm that there is now only one display and that it is primary
+            // and mirroring is enabled.
+            expectEquals(1, displayPage.displays.length);
+            expectEquals(
+                displayPage.displays[0].id, displayPage.selectedDisplay.id);
+            expectTrue(displayPage.displays[0].isPrimary);
+            expectTrue(displayPage.showMirror_(false, displayPage.displays));
+            expectTrue(displayPage.isMirrored_(displayPage.displays));
+          });
     });
 
     suite(assert(TestNames.Power), function() {
@@ -692,7 +714,7 @@
         });
 
         setup(function() {
-          return showAndGetDeviceSubpage('power', settings.Route.POWER)
+          return showAndGetDeviceSubpage('power', settings.routes.POWER)
               .then(function(page) {
                 powerPage = page;
                 powerSourceRow = assert(powerPage.$$('#powerSourceRow'));
@@ -933,8 +955,8 @@
       });
 
       setup(function() {
-        return showAndGetDeviceSubpage('stylus', settings.Route.STYLUS).then(
-            function(page) {
+        return showAndGetDeviceSubpage('stylus', settings.routes.STYLUS)
+            .then(function(page) {
               stylusPage = page;
               browserProxy = settings.DevicePageBrowserProxyImpl.getInstance();
               appSelector = assert(page.$$('#menu'));
diff --git a/chrome/test/data/webui/settings/people_page_change_picture_test.js b/chrome/test/data/webui/settings/people_page_change_picture_test.js
index 627c43ba..3928ff8 100644
--- a/chrome/test/data/webui/settings/people_page_change_picture_test.js
+++ b/chrome/test/data/webui/settings/people_page_change_picture_test.js
@@ -82,8 +82,7 @@
     suite('ChangePictureTests', function() {
       var changePicture = null;
       var browserProxy = null;
-      var crCamera = null;
-      var discardControlBar = null;
+      var crPicturePreview = null;
 
       suiteSetup(function() {
         loadTimeData.overrideValues({
@@ -98,12 +97,10 @@
         changePicture = document.createElement('settings-change-picture');
         document.body.appendChild(changePicture);
 
-        crCamera = changePicture.$$('cr-camera');
-        assertTrue(!!crCamera);
-        discardControlBar = changePicture.$.discardControlBar;
-        assertTrue(!!discardControlBar);
+        crPicturePreview = changePicture.$$('cr-picture-preview');
+        assertTrue(!!crPicturePreview);
 
-        changePicture.currentRouteChanged(settings.Route.CHANGE_PICTURE);
+        changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
 
         return browserProxy.whenCalled('initialize').then(function() {
           Polymer.dom.flush();
@@ -120,27 +117,44 @@
         cr.webUIListenerCallback('camera-presence-changed', false);
         Polymer.dom.flush();
 
-        expectTrue(cameraIcon.hidden);
-        expectFalse(crCamera.cameraActive);
+        return new Promise(function(resolve) {
+          changePicture.async(resolve);
+        }).then(function() {
+          expectTrue(cameraIcon.hidden);
+          expectFalse(crPicturePreview.cameraPresent);
+          expectFalse(crPicturePreview.cameraActive_);
 
-        cr.webUIListenerCallback('camera-presence-changed', true);
-        Polymer.dom.flush();
+          cr.webUIListenerCallback('camera-presence-changed', true);
+          Polymer.dom.flush();
+          return new Promise(function(resolve) {
+            changePicture.async(resolve);
+          });
+        }).then(function() {
+          expectFalse(cameraIcon.hidden);
+          expectTrue(crPicturePreview.cameraPresent);
+          expectFalse(crPicturePreview.cameraActive_);
 
-        expectFalse(cameraIcon.hidden);
-        expectFalse(crCamera.cameraActive);
+          MockInteractions.tap(cameraIcon);
+          Polymer.dom.flush();
+          return new Promise(function(resolve) {
+            changePicture.async(resolve);
+          });
+        }).then(function() {
+          expectFalse(cameraIcon.hidden);
+          expectTrue(crPicturePreview.cameraActive_);
+          expectEquals(CrPicture.SelectionTypes.CAMERA,
+                       changePicture.selectedItem_.dataset.type);
+          var discard = crPicturePreview.$$('#discard');
+          expectTrue(!discard || discard.hidden);
 
-        MockInteractions.tap(cameraIcon);
-
-        Polymer.dom.flush();
-        expectFalse(cameraIcon.hidden);
-        expectTrue(crCamera.cameraActive);
-        expectEquals(ChangePictureSelectionTypes.CAMERA,
-                     changePicture.selectedItem_.dataset.type);
-        expectTrue(discardControlBar.hidden);
-
-        // Ensure that the camera is deactivated if user navigates away.
-        changePicture.currentRouteChanged(settings.Route.BASIC);
-        expectFalse(crCamera.cameraActive);
+          // Ensure that the camera is deactivated if user navigates away.
+          changePicture.currentRouteChanged(settings.routes.BASIC);
+          return new Promise(function(resolve) {
+            changePicture.async(resolve);
+          });
+        }).then(function() {
+          expectFalse(crPicturePreview.cameraActive_);
+        });
       });
 
       test('ChangePictureProfileImage', function() {
@@ -153,16 +167,17 @@
         return browserProxy.whenCalled('selectProfileImage').then(function() {
           Polymer.dom.flush();
 
-          expectEquals(ChangePictureSelectionTypes.PROFILE,
+          expectEquals(CrPicture.SelectionTypes.PROFILE,
                        changePicture.selectedItem_.dataset.type);
-          expectFalse(crCamera.cameraActive);
-          expectTrue(discardControlBar.hidden);
+          expectFalse(crPicturePreview.cameraActive_);
+          var discard = crPicturePreview.$$('#discard');
+          expectTrue(!discard || discard.hidden);
 
           // Ensure that the selection is restored after navigating away and
           // then back to the subpage.
-          changePicture.currentRouteChanged(settings.Route.BASIC);
-          changePicture.currentRouteChanged(settings.Route.CHANGE_PICTURE);
-          expectEquals(ChangePictureSelectionTypes.PROFILE,
+          changePicture.currentRouteChanged(settings.routes.BASIC);
+          changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
+          expectEquals(CrPicture.SelectionTypes.PROFILE,
                        changePicture.selectedItem_.dataset.type);
         });
       });
@@ -178,11 +193,13 @@
 
         // Expect the old image to be selected once an old image is sent via
         // the native interface.
-        expectEquals(ChangePictureSelectionTypes.OLD,
+        expectEquals(CrPicture.SelectionTypes.OLD,
                      changePicture.selectedItem_.dataset.type);
         expectFalse(oldImage.hidden);
-        expectFalse(crCamera.cameraActive);
-        expectFalse(discardControlBar.hidden);
+        expectFalse(crPicturePreview.cameraActive_);
+        var discard = crPicturePreview.$$('#discard');
+        assertTrue(!!discard);
+        expectFalse(discard.hidden);
       });
 
       test('ChangePictureSelectFirstDefaultImage', function() {
@@ -196,11 +213,12 @@
               expectEquals('chrome://foo/1.png', args[0]);
 
               Polymer.dom.flush();
-              expectEquals(ChangePictureSelectionTypes.DEFAULT,
+              expectEquals(CrPicture.SelectionTypes.DEFAULT,
                            changePicture.selectedItem_.dataset.type);
               expectEquals(firstDefaultImage, changePicture.selectedItem_);
-              expectFalse(crCamera.cameraActive);
-              expectTrue(discardControlBar.hidden);
+              expectFalse(crPicturePreview.cameraActive_);
+              var discard = crPicturePreview.$$('#discard');
+              expectTrue(!discard || discard.hidden);
 
               // Now verify that arrow keys actually select the new image.
               browserProxy.resetResolver('selectDefaultImage');
@@ -215,8 +233,6 @@
       test('ChangePictureRestoreImageAfterDiscard', function() {
         var firstDefaultImage = changePicture.$$('img[data-type="default"]');
         assertTrue(!!firstDefaultImage);
-        var discardOldImage = changePicture.$.discardOldImage;
-        assertTrue(!!discardOldImage);
 
         MockInteractions.tap(firstDefaultImage);
 
@@ -227,10 +243,12 @@
           cr.webUIListenerCallback('old-image-changed', 'fake-old-image.jpg');
 
           Polymer.dom.flush();
-          expectEquals(ChangePictureSelectionTypes.OLD,
+          expectEquals(CrPicture.SelectionTypes.OLD,
                        changePicture.selectedItem_.dataset.type);
 
-          MockInteractions.tap(discardOldImage);
+          var discardButton = crPicturePreview.$$('#discard button');
+          assertTrue(!!discardButton);
+          MockInteractions.tap(discardButton);
 
           Polymer.dom.flush();
           expectEquals(firstDefaultImage, changePicture.selectedItem_);
diff --git a/chrome/test/data/webui/settings/people_page_manage_profile_test.js b/chrome/test/data/webui/settings/people_page_manage_profile_test.js
index 09050485..8780b66 100644
--- a/chrome/test/data/webui/settings/people_page_manage_profile_test.js
+++ b/chrome/test/data/webui/settings/people_page_manage_profile_test.js
@@ -87,7 +87,7 @@
         manageProfile.profileName = 'Initial Fake Name';
         manageProfile.syncStatus = {supervisedUser: false, childUser: false};
         document.body.appendChild(manageProfile);
-        settings.navigateTo(settings.Route.MANAGE_PROFILE);
+        settings.navigateTo(settings.routes.MANAGE_PROFILE);
       });
 
       teardown(function() { manageProfile.remove(); });
@@ -193,7 +193,7 @@
       // Tests profile shortcut toggle is visible and toggling it removes and
       // creates the profile shortcut respectively.
       test('ManageProfileShortcutToggle', function() {
-        settings.navigateTo(settings.Route.MANAGE_PROFILE);
+        settings.navigateTo(settings.routes.MANAGE_PROFILE);
         Polymer.dom.flush();
 
         assertFalse(!!manageProfile.$$('#hasShortcutToggle'));
@@ -230,7 +230,7 @@
         browserProxy.setProfileShortcutStatus(
             ProfileShortcutStatus.PROFILE_SHORTCUT_NOT_FOUND);
 
-        settings.navigateTo(settings.Route.MANAGE_PROFILE);
+        settings.navigateTo(settings.routes.MANAGE_PROFILE);
         Polymer.dom.flush();
 
         assertFalse(!!manageProfile.$$('#hasShortcutToggle'));
@@ -252,7 +252,7 @@
         browserProxy.setProfileShortcutStatus(
             ProfileShortcutStatus.PROFILE_SHORTCUT_SETTING_HIDDEN);
 
-        settings.navigateTo(settings.Route.MANAGE_PROFILE);
+        settings.navigateTo(settings.routes.MANAGE_PROFILE);
         Polymer.dom.flush();
 
         assertFalse(!!manageProfile.$$('#hasShortcutToggle'));
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_test.js b/chrome/test/data/webui/settings/people_page_sync_page_test.js
index 686ff4c2..8458b79 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_page_test.js
@@ -106,7 +106,7 @@
 
         PolymerTest.clearBody();
         syncPage = document.createElement('settings-sync-page');
-        settings.navigateTo(settings.Route.SYNC);
+        settings.navigateTo(settings.routes.SYNC);
 
         document.body.appendChild(syncPage);
 
@@ -132,13 +132,13 @@
 
       test('NotifiesHandlerOfNavigation', function() {
         function testNavigateAway() {
-          settings.navigateTo(settings.Route.PEOPLE);
+          settings.navigateTo(settings.routes.PEOPLE);
           return browserProxy.whenCalled('didNavigateAwayFromSyncPage');
         }
 
         function testNavigateBack() {
           browserProxy.resetResolver('didNavigateToSyncPage');
-          settings.navigateTo(settings.Route.SYNC);
+          settings.navigateTo(settings.routes.SYNC);
           return browserProxy.whenCalled('didNavigateToSyncPage');
         }
 
@@ -151,7 +151,7 @@
         function testRecreate() {
           browserProxy.resetResolver('didNavigateToSyncPage');
           syncPage = document.createElement('settings-sync-page');
-          settings.navigateTo(settings.Route.SYNC);
+          settings.navigateTo(settings.routes.SYNC);
 
           document.body.appendChild(syncPage);
           return browserProxy.whenCalled('didNavigateToSyncPage');
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index ca99ca1..8a6e3107 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -281,7 +281,7 @@
 
       test('NavigateDirectlyToSignOutURL', function() {
         // Navigate to chrome://md-settings/signOut
-        settings.navigateTo(settings.Route.SIGN_OUT);
+        settings.navigateTo(settings.routes.SIGN_OUT);
 
         return new Promise(
             function(resolve) { peoplePage.async(resolve); }).then(function() {
@@ -303,30 +303,35 @@
       });
 
       test('Signout dialog suppressed when not signed in', function() {
-        return browserProxy.whenCalled('getSyncStatus').then(function() {
-          settings.navigateTo(settings.Route.SIGN_OUT);
-          return new Promise(function(resolve) { peoplePage.async(resolve); });
-        }).then(function() {
-          assertTrue(peoplePage.$$('#disconnectDialog').open);
+        return browserProxy.whenCalled('getSyncStatus')
+            .then(function() {
+              settings.navigateTo(settings.routes.SIGN_OUT);
+              return new Promise(function(resolve) {
+                peoplePage.async(resolve);
+              });
+            })
+            .then(function() {
+              assertTrue(peoplePage.$$('#disconnectDialog').open);
 
-          var popstatePromise = new Promise(function(resolve) {
-            listenOnce(window, 'popstate', resolve);
-          });
+              var popstatePromise = new Promise(function(resolve) {
+                listenOnce(window, 'popstate', resolve);
+              });
 
-          cr.webUIListenerCallback('sync-status-changed', {
-            signedIn: false,
-          });
+              cr.webUIListenerCallback('sync-status-changed', {
+                signedIn: false,
+              });
 
-          return popstatePromise;
-        }).then(function() {
-          var popstatePromise = new Promise(function(resolve) {
-            listenOnce(window, 'popstate', resolve);
-          });
+              return popstatePromise;
+            })
+            .then(function() {
+              var popstatePromise = new Promise(function(resolve) {
+                listenOnce(window, 'popstate', resolve);
+              });
 
-          settings.navigateTo(settings.Route.SIGN_OUT);
+              settings.navigateTo(settings.routes.SIGN_OUT);
 
-          return popstatePromise;
-        });
+              return popstatePromise;
+            });
       });
 
       test('syncStatusNotActionableForManagedAccounts', function() {
diff --git a/chrome/test/data/webui/settings/reset_page_test.js b/chrome/test/data/webui/settings/reset_page_test.js
index 5316a9b..2c390135 100644
--- a/chrome/test/data/webui/settings/reset_page_test.js
+++ b/chrome/test/data/webui/settings/reset_page_test.js
@@ -132,7 +132,7 @@
       }
 
       test(TestNames.ResetProfileDialogOriginUnknown, function() {
-        settings.navigateTo(settings.Route.RESET_DIALOG);
+        settings.navigateTo(settings.routes.RESET_DIALOG);
         return resetPageBrowserProxy.whenCalled('onShowResetProfileDialog')
             .then(function() { return testResetRequestOrigin(''); });
       });
@@ -144,7 +144,7 @@
       });
 
       test(TestNames.ResetProfileDialogOriginTriggeredReset, function() {
-        settings.navigateTo(settings.Route.TRIGGERED_RESET_DIALOG);
+        settings.navigateTo(settings.routes.TRIGGERED_RESET_DIALOG);
         return resetPageBrowserProxy.whenCalled('onShowResetProfileDialog')
             .then(function() {
               return testResetRequestOrigin('triggeredreset');
diff --git a/chrome/test/data/webui/settings/reset_profile_banner_test.js b/chrome/test/data/webui/settings/reset_profile_banner_test.js
index a01829a..18f15b2 100644
--- a/chrome/test/data/webui/settings/reset_profile_banner_test.js
+++ b/chrome/test/data/webui/settings/reset_profile_banner_test.js
@@ -20,9 +20,9 @@
   // Tests that the reset profile banner navigates to the Reset profile dialog
   // URL when the "reset all settings" button is clicked.
   test('ResetBannerReset', function() {
-    assertNotEquals(settings.Route.RESET_DIALOG, settings.getCurrentRoute());
+    assertNotEquals(settings.routes.RESET_DIALOG, settings.getCurrentRoute());
     MockInteractions.tap(resetBanner.$.reset);
-    assertEquals(settings.Route.RESET_DIALOG, settings.getCurrentRoute());
+    assertEquals(settings.routes.RESET_DIALOG, settings.getCurrentRoute());
     assertFalse(resetBanner.$.dialog.open);
   });
 
diff --git a/chrome/test/data/webui/settings/route_tests.js b/chrome/test/data/webui/settings/route_tests.js
index ab0c682..a7041aa 100644
--- a/chrome/test/data/webui/settings/route_tests.js
+++ b/chrome/test/data/webui/settings/route_tests.js
@@ -89,7 +89,7 @@
 
   test('no duplicate routes', function() {
     var paths = new Set();
-    Object.values(settings.Route).forEach(function(route) {
+    Object.values(settings.routes).forEach(function(route) {
       assertFalse(paths.has(route.path), route.path);
       paths.add(route.path);
     });
@@ -97,111 +97,135 @@
 
   test('navigate back to parent previous route', function() {
     return testNavigateBackUsesHistory(
-        settings.Route.BASIC,
-        settings.Route.PEOPLE,
-        settings.Route.BASIC);
+        settings.routes.BASIC, settings.routes.PEOPLE, settings.routes.BASIC);
   });
 
   test('navigate back to non-ancestor shallower route', function() {
     return testNavigateBackUsesHistory(
-        settings.Route.ADVANCED,
-        settings.Route.PEOPLE,
-        settings.Route.BASIC);
+        settings.routes.ADVANCED, settings.routes.PEOPLE,
+        settings.routes.BASIC);
   });
 
   test('navigate back to sibling route', function() {
     return testNavigateBackUsesHistory(
-        settings.Route.APPEARANCE,
-        settings.Route.PEOPLE,
-        settings.Route.APPEARANCE);
+        settings.routes.APPEARANCE, settings.routes.PEOPLE,
+        settings.routes.APPEARANCE);
   });
 
   test('navigate back to parent when previous route is deeper', function() {
-    settings.navigateTo(settings.Route.SYNC);
-    settings.navigateTo(settings.Route.PEOPLE);
+    settings.navigateTo(settings.routes.SYNC);
+    settings.navigateTo(settings.routes.PEOPLE);
     settings.navigateToPreviousRoute();
-    assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
+    assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
   });
 
   test('navigate back to BASIC when going back from root pages', function() {
-    settings.navigateTo(settings.Route.PEOPLE);
-    settings.navigateTo(settings.Route.ADVANCED);
+    settings.navigateTo(settings.routes.PEOPLE);
+    settings.navigateTo(settings.routes.ADVANCED);
     settings.navigateToPreviousRoute();
-    assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
+    assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
   });
 
   test('navigateTo respects removeSearch optional parameter', function() {
     var params = new URLSearchParams('search=foo');
-    settings.navigateTo(settings.Route.BASIC, params);
+    settings.navigateTo(settings.routes.BASIC, params);
     assertEquals(params.toString(), settings.getQueryParameters().toString());
 
     settings.navigateTo(
-        settings.Route.SITE_SETTINGS, null, /* removeSearch */ false);
+        settings.routes.SITE_SETTINGS, null,
+        /* removeSearch */ false);
     assertEquals(params.toString(), settings.getQueryParameters().toString());
 
     settings.navigateTo(
-        settings.Route.SEARCH_ENGINES, null, /* removeSearch */ true);
+        settings.routes.SEARCH_ENGINES, null,
+        /* removeSearch */ true);
     assertEquals('', settings.getQueryParameters().toString());
   });
 
   test('navigateTo ADVANCED forwards to BASIC', function() {
-    settings.navigateTo(settings.Route.ADVANCED);
-    assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
+    settings.navigateTo(settings.routes.ADVANCED);
+    assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
   });
 
   test('popstate flag works', function() {
-    settings.navigateTo(settings.Route.BASIC);
+    settings.navigateTo(settings.routes.BASIC);
     assertFalse(settings.lastRouteChangeWasPopstate());
 
-    settings.navigateTo(settings.Route.PEOPLE);
+    settings.navigateTo(settings.routes.PEOPLE);
     assertFalse(settings.lastRouteChangeWasPopstate());
 
     return whenPopState(function() {
-      window.history.back();
-    }).then(function() {
-      assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
-      assertTrue(settings.lastRouteChangeWasPopstate());
+             window.history.back();
+           })
+        .then(function() {
+          assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
+          assertTrue(settings.lastRouteChangeWasPopstate());
 
-      settings.navigateTo(settings.Route.ADVANCED);
-      assertFalse(settings.lastRouteChangeWasPopstate());
-    });
+          settings.navigateTo(settings.routes.ADVANCED);
+          assertFalse(settings.lastRouteChangeWasPopstate());
+        });
   });
 
   test('getRouteForPath trailing slashes', function() {
-    assertEquals(settings.Route.BASIC, settings.getRouteForPath('/'));
+    assertEquals(settings.routes.BASIC, settings.getRouteForPath('/'));
     assertEquals(null, settings.getRouteForPath('//'));
 
     // Simple path.
-    assertEquals(settings.Route.PEOPLE, settings.getRouteForPath('/people/'));
-    assertEquals(settings.Route.PEOPLE, settings.getRouteForPath('/people'));
+    assertEquals(settings.routes.PEOPLE, settings.getRouteForPath('/people/'));
+    assertEquals(settings.routes.PEOPLE, settings.getRouteForPath('/people'));
 
     // Path with a slash.
     assertEquals(
-        settings.Route.SITE_SETTINGS_COOKIES,
+        settings.routes.SITE_SETTINGS_COOKIES,
         settings.getRouteForPath('/content/cookies'));
     assertEquals(
-        settings.Route.SITE_SETTINGS_COOKIES,
+        settings.routes.SITE_SETTINGS_COOKIES,
         settings.getRouteForPath('/content/cookies/'));
 
     if (cr.isChromeOS) {
       // Path with a dash.
       assertEquals(
-          settings.Route.KEYBOARD,
+          settings.routes.KEYBOARD,
           settings.getRouteForPath('/keyboard-overlay'));
       assertEquals(
-          settings.Route.KEYBOARD,
+          settings.routes.KEYBOARD,
           settings.getRouteForPath('/keyboard-overlay/'));
     }
   });
 
   test('isNavigableDialog', function() {
-    assertTrue(settings.Route.CLEAR_BROWSER_DATA.isNavigableDialog);
-    assertTrue(settings.Route.IMPORT_DATA.isNavigableDialog);
-    assertTrue(settings.Route.RESET_DIALOG.isNavigableDialog);
-    assertTrue(settings.Route.SIGN_OUT.isNavigableDialog);
-    assertTrue(settings.Route.TRIGGERED_RESET_DIALOG.isNavigableDialog);
+    assertTrue(settings.routes.CLEAR_BROWSER_DATA.isNavigableDialog);
+    assertTrue(settings.routes.IMPORT_DATA.isNavigableDialog);
+    assertTrue(settings.routes.RESET_DIALOG.isNavigableDialog);
+    assertTrue(settings.routes.SIGN_OUT.isNavigableDialog);
+    assertTrue(settings.routes.TRIGGERED_RESET_DIALOG.isNavigableDialog);
 
-    assertFalse(settings.Route.PRIVACY.isNavigableDialog);
-    assertFalse(settings.Route.DEFAULT_BROWSER.isNavigableDialog);
+    assertFalse(settings.routes.PRIVACY.isNavigableDialog);
+    assertFalse(settings.routes.DEFAULT_BROWSER.isNavigableDialog);
+  });
+
+  test('pageVisibility affects route availability', function() {
+    settings.pageVisibility = {
+      advancedSettings: false,
+      appearance: false,
+      defaultBrowser: false,
+      onStartup: false,
+      passwordsAndForms: false,
+      people: false,
+      reset: false,
+    };
+
+    var router = new settings.Router();
+    var hasRoute = route => router.getRoutes().hasOwnProperty(route);
+
+    assertTrue(hasRoute('BASIC'));
+
+    assertFalse(hasRoute('ADVANCED'));
+    assertFalse(hasRoute('APPEARANCE'));
+    assertFalse(hasRoute('DEFAULT_BROWSER'));
+    assertFalse(hasRoute('ON_STARTUP'));
+    assertFalse(hasRoute('PASSWORDS'));
+    assertFalse(hasRoute('PEOPLE'));
+    assertFalse(hasRoute('RESET'));
   });
 });
diff --git a/chrome/test/data/webui/settings/settings_animated_pages_test.js b/chrome/test/data/webui/settings/settings_animated_pages_test.js
index 1b2052e..f792934 100644
--- a/chrome/test/data/webui/settings/settings_animated_pages_test.js
+++ b/chrome/test/data/webui/settings/settings_animated_pages_test.js
@@ -6,11 +6,11 @@
   test('focuses subpage trigger when exiting subpage', function(done) {
     document.body.innerHTML = `
       <settings-animated-pages
-          section="${settings.Route.SEARCH_ENGINES.section}">
+          section="${settings.routes.SEARCH_ENGINES.section}">
         <neon-animatable route-path="default">
           <button id="subpage-trigger"></button>
         </neon-animatable>
-        <neon-animatable route-path="${settings.Route.SEARCH_ENGINES.path}">
+        <neon-animatable route-path="${settings.routes.SEARCH_ENGINES.path}">
           <button id="subpage-trigger"></button>
         </neon-animatable>
       </settings-animated-pages>`;
@@ -18,15 +18,15 @@
     var animatedPages = document.body.querySelector('settings-animated-pages');
     animatedPages.focusConfig = new Map();
     animatedPages.focusConfig.set(
-        settings.Route.SEARCH_ENGINES.path, '#subpage-trigger');
+        settings.routes.SEARCH_ENGINES.path, '#subpage-trigger');
 
     var trigger = document.body.querySelector('#subpage-trigger');
     assertTrue(!!trigger);
     trigger.addEventListener('focus', function() { done(); });
 
     // Trigger subpage exit navigation.
-    settings.navigateTo(settings.Route.BASIC);
-    settings.navigateTo(settings.Route.SEARCH_ENGINES);
+    settings.navigateTo(settings.routes.BASIC);
+    settings.navigateTo(settings.routes.SEARCH_ENGINES);
     settings.navigateToPreviousRoute();
   });
 });
diff --git a/chrome/test/data/webui/settings/settings_main_test.js b/chrome/test/data/webui/settings/settings_main_test.js
index 9d03322..fb2b11ab 100644
--- a/chrome/test/data/webui/settings/settings_main_test.js
+++ b/chrome/test/data/webui/settings/settings_main_test.js
@@ -64,7 +64,7 @@
       var settingsMain = null;
 
       setup(function() {
-        settings.navigateTo(settings.Route.BASIC);
+        settings.navigateTo(settings.routes.BASIC);
         searchManager = new TestSearchManager();
         settings.setSearchManagerForTesting(searchManager);
         PolymerTest.clearBody();
@@ -205,7 +205,7 @@
             })
             .then(function() {
               // Imitate behavior of clearing search.
-              settings.navigateTo(settings.Route.BASIC);
+              settings.navigateTo(settings.routes.BASIC);
               Polymer.dom.flush();
               return assertPageVisibility('block', expectedAdvanced);
             });
@@ -213,7 +213,7 @@
 
       test('exiting search mode, advanced collapsed', function() {
         // Simulating searching while the advanced page is collapsed.
-        settingsMain.currentRouteChanged(settings.Route.BASIC);
+        settingsMain.currentRouteChanged(settings.routes.BASIC);
         Polymer.dom.flush();
         return assertAdvancedVisibilityAfterSearch('none');
       });
@@ -222,7 +222,7 @@
       // "advanced" page, when the search has been initiated from a subpage
       // whose parent is the "advanced" page.
       test('exiting search mode, advanced expanded', function() {
-        settings.navigateTo(settings.Route.SITE_SETTINGS);
+        settings.navigateTo(settings.routes.SITE_SETTINGS);
         Polymer.dom.flush();
         return assertAdvancedVisibilityAfterSearch('block');
       });
@@ -231,25 +231,25 @@
       // lands the user in a page where both basic and advanced sections are
       // visible, because the page is still in search mode.
       test('returning from subpage to search results', function() {
-        settings.navigateTo(settings.Route.BASIC);
+        settings.navigateTo(settings.routes.BASIC);
         Polymer.dom.flush();
 
         searchManager.setMatchesFound(true);
         return settingsMain.searchContents('Query1').then(function() {
           // Simulate navigating into a subpage.
-          settings.navigateTo(settings.Route.SEARCH_ENGINES);
+          settings.navigateTo(settings.routes.SEARCH_ENGINES);
           settingsMain.$$('settings-basic-page').fire('subpage-expand');
           Polymer.dom.flush();
 
           // Simulate clicking the left arrow to go back to the search results.
-          settings.navigateTo(settings.Route.BASIC);
+          settings.navigateTo(settings.routes.BASIC);
           return assertPageVisibility('block', 'block');
         });
       });
 
       // TODO(michaelpg): Move these to a new test for settings-basic-page.
       test('can collapse advanced on advanced section route', function() {
-        settings.navigateTo(settings.Route.PRIVACY);
+        settings.navigateTo(settings.routes.PRIVACY);
         Polymer.dom.flush();
 
         var basicPage = settingsMain.$$('settings-basic-page');
@@ -274,12 +274,12 @@
       });
 
       test('navigating to a basic page does not collapse advanced', function() {
-        settings.navigateTo(settings.Route.PRIVACY);
+        settings.navigateTo(settings.routes.PRIVACY);
         Polymer.dom.flush();
 
         assertToggleContainerVisible(true);
 
-        settings.navigateTo(settings.Route.PEOPLE);
+        settings.navigateTo(settings.routes.PEOPLE);
         Polymer.dom.flush();
 
         return assertPageVisibility('block', 'block');
diff --git a/chrome/test/data/webui/settings/settings_menu_test.js b/chrome/test/data/webui/settings/settings_menu_test.js
index 9752927..2366909 100644
--- a/chrome/test/data/webui/settings/settings_menu_test.js
+++ b/chrome/test/data/webui/settings/settings_menu_test.js
@@ -63,7 +63,7 @@
       // search URL parameter.
       test('clearsUrlSearchParam', function() {
         var urlParams = new URLSearchParams('search=foo');
-        settings.navigateTo(settings.Route.BASIC, urlParams);
+        settings.navigateTo(settings.routes.BASIC, urlParams);
         assertEquals(
             urlParams.toString(),
             settings.getQueryParameters().toString());
@@ -75,7 +75,7 @@
     suite('SettingsMenuReset', function() {
       setup(function() {
         PolymerTest.clearBody();
-        settings.navigateTo(settings.Route.RESET, '');
+        settings.navigateTo(settings.routes.RESET, '');
         settingsMenu = document.createElement('settings-menu');
         document.body.appendChild(settingsMenu);
       });
@@ -93,7 +93,7 @@
         var path = new window.URL(selector.selected).pathname;
         assertEquals('/reset', path);
 
-        settings.navigateTo(settings.Route.PEOPLE, '');
+        settings.navigateTo(settings.routes.PEOPLE, '');
         Polymer.dom.flush();
 
         path = new window.URL(selector.selected).pathname;
@@ -105,7 +105,7 @@
         var path = new window.URL(selector.selected).pathname;
         assertEquals('/reset', path);
 
-        settings.navigateTo(settings.Route.BASIC, '');
+        settings.navigateTo(settings.routes.BASIC, '');
         Polymer.dom.flush();
 
         // BASIC has no sub page selected.
diff --git a/chrome/test/data/webui/settings/settings_subpage_test.js b/chrome/test/data/webui/settings/settings_subpage_test.js
index 343c7ada..1ab14db 100644
--- a/chrome/test/data/webui/settings/settings_subpage_test.js
+++ b/chrome/test/data/webui/settings/settings_subpage_test.js
@@ -9,23 +9,23 @@
 
       // Pretend that we initially started on the CERTIFICATES route.
       window.history.replaceState(
-          undefined, '', settings.Route.CERTIFICATES.path);
+          undefined, '', settings.routes.CERTIFICATES.path);
       settings.initializeRouteFromUrl();
-      assertEquals(settings.Route.CERTIFICATES, settings.getCurrentRoute());
+      assertEquals(settings.routes.CERTIFICATES, settings.getCurrentRoute());
 
       var subpage = document.createElement('settings-subpage');
       document.body.appendChild(subpage);
 
       MockInteractions.tap(subpage.$$('button'));
-      assertEquals(settings.Route.PRIVACY, settings.getCurrentRoute());
+      assertEquals(settings.routes.PRIVACY, settings.getCurrentRoute());
     });
 
     test('navigates to any route via window.back()', function(done) {
       PolymerTest.clearBody();
 
-      settings.navigateTo(settings.Route.BASIC);
-      settings.navigateTo(settings.Route.SYNC);
-      assertEquals(settings.Route.SYNC, settings.getCurrentRoute());
+      settings.navigateTo(settings.routes.BASIC);
+      settings.navigateTo(settings.routes.SYNC);
+      assertEquals(settings.routes.SYNC, settings.getCurrentRoute());
 
       var subpage = document.createElement('settings-subpage');
       document.body.appendChild(subpage);
@@ -33,7 +33,7 @@
       MockInteractions.tap(subpage.$$('button'));
 
       window.addEventListener('popstate', function(event) {
-        assertEquals(settings.Route.BASIC, settings.getCurrentRoute());
+        assertEquals(settings.routes.BASIC, settings.getCurrentRoute());
         done();
       });
     });
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js
index 22813ab..79705a2 100644
--- a/chrome/test/data/webui/settings/settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -116,7 +116,7 @@
 
       var query = 'foo';
       settings.navigateTo(
-          settings.Route.BASIC, new URLSearchParams(`search=${query}`));
+          settings.routes.BASIC, new URLSearchParams(`search=${query}`));
       assertEquals(query, searchField.getSearchInput().value);
     });
 
@@ -125,7 +125,7 @@
           toolbar.getSearchField());
 
       settings.navigateTo(
-          settings.Route.BASIC, /* dynamicParams */ null,
+          settings.routes.BASIC, /* dynamicParams */ null,
           /* removeSearch */ true);
       assertEquals('', searchField.getSearchInput().value);
       assertFalse(settings.getQueryParameters().has('search'));
diff --git a/chrome/test/data/webui/settings/site_data_details_subpage_tests.js b/chrome/test/data/webui/settings/site_data_details_subpage_tests.js
index 43b5051..a48b65c6 100644
--- a/chrome/test/data/webui/settings/site_data_details_subpage_tests.js
+++ b/chrome/test/data/webui/settings/site_data_details_subpage_tests.js
@@ -41,7 +41,7 @@
     PolymerTest.clearBody();
     page = document.createElement('site-data-details-subpage');
     settings.navigateTo(
-        settings.Route.SITE_SETTINGS_DATA_DETAILS,
+        settings.routes.SITE_SETTINGS_DATA_DETAILS,
         new URLSearchParams('site=' + site));
 
     document.body.appendChild(page);
diff --git a/chrome/utility/safe_browsing/mac/BUILD.gn b/chrome/utility/safe_browsing/mac/BUILD.gn
index 60d6979..2f3ee334d 100644
--- a/chrome/utility/safe_browsing/mac/BUILD.gn
+++ b/chrome/utility/safe_browsing/mac/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/sysroot.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 
 source_set("mac") {
@@ -48,6 +49,19 @@
   public_configs = [ ":dmg_public_config" ]
 }
 
+config("10_10_config") {
+  cflags = [
+    "-isysroot",
+    sysroot,
+    "-mmacosx-version-min=10.10",
+  ]
+  ldflags = [
+    "-isysroot",
+    sysroot,
+    "-mmacosx-version-min=10.10",
+  ]
+}
+
 executable("crdmg") {
   sources = [
     "crdmg.cc",
@@ -58,6 +72,9 @@
     "//base",
     "//sandbox/mac:seatbelt",
   ]
+
+  configs -= [ "//build/config/compiler:runtime_library" ]
+  configs += [ ":10_10_config" ]
 }
 
 fuzzer_test("safe_browsing_dmg_fuzzer") {
diff --git a/chrome/utility/safe_browsing/mac/crdmg.cc b/chrome/utility/safe_browsing/mac/crdmg.cc
index dcaaa8d..d73333e 100644
--- a/chrome/utility/safe_browsing/mac/crdmg.cc
+++ b/chrome/utility/safe_browsing/mac/crdmg.cc
@@ -26,14 +26,6 @@
 #include "chrome/utility/safe_browsing/mac/udif.h"
 #include "sandbox/mac/seatbelt.h"
 
-// This executable only works on 10.10+, so unconditionally use these functions
-// to make sandboxing easier.
-extern "C" {
-int mkdirat(int, const char *, mode_t);
-int openat(int, const char *, int, ...);
-int unlinkat(int, const char *, int);
-}
-
 namespace {
 
 // SafeDMG (crdmg) is a utility that can perform a list or extract operation
diff --git a/chromecast/browser/cast_net_log.cc b/chromecast/browser/cast_net_log.cc
index bd065822..e281054 100644
--- a/chromecast/browser/cast_net_log.cc
+++ b/chromecast/browser/cast_net_log.cc
@@ -8,14 +8,15 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_file.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "content/public/common/content_switches.h"
+#include "net/log/file_net_log_observer.h"
 #include "net/log/net_log_util.h"
-#include "net/log/write_to_file_net_log_observer.h"
 
 namespace chromecast {
 
@@ -41,39 +42,25 @@
 }  // namespace
 
 CastNetLog::CastNetLog() {
-  // TODO(derekjchow): This code is virtually identical to ShellNetLog which is
-  //     nearly identical to code in ChromeNetLog. Consider merging the code.
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
   if (command_line->HasSwitch(switches::kLogNetLog)) {
     base::FilePath log_path =
         command_line->GetSwitchValuePath(switches::kLogNetLog);
-    // Much like logging.h, bypass threading restrictions by using fopen
-    // directly.  Have to write on a thread that's shutdown to handle events on
-    // shutdown properly, and posting events to another thread as they occur
-    // would result in an unbounded buffer size, so not much can be gained by
-    // doing this on another thread.  It's only used when debugging, so
-    // performance is not a big concern.
-    base::ScopedFILE file;
-    file.reset(fopen(log_path.value().c_str(), "w"));
+    net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::Default();
 
-    if (!file) {
-      LOG(ERROR) << "Could not open file " << log_path.value()
-                 << " for net logging";
-    } else {
-      std::unique_ptr<base::Value> constants(GetShellConstants());
-      write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
-      write_to_file_observer_->StartObserving(this, std::move(file),
-                                              constants.get(), nullptr);
-    }
+    file_net_log_observer_ =
+        net::FileNetLogObserver::CreateUnbounded(log_path, GetShellConstants());
+
+    file_net_log_observer_->StartObserving(this, capture_mode);
   }
 }
 
 CastNetLog::~CastNetLog() {
   // Remove the observer we own before we're destroyed.
-  if (write_to_file_observer_)
-    write_to_file_observer_->StopObserving(nullptr);
+  if (file_net_log_observer_)
+    file_net_log_observer_->StopObserving(nullptr, base::OnceClosure());
 }
 
 }  // namespace chromecast
diff --git a/chromecast/browser/cast_net_log.h b/chromecast/browser/cast_net_log.h
index fe3e4b3..bdf143a 100644
--- a/chromecast/browser/cast_net_log.h
+++ b/chromecast/browser/cast_net_log.h
@@ -9,7 +9,11 @@
 #include <string>
 
 #include "base/macros.h"
-#include "net/log/write_to_file_net_log_observer.h"
+#include "net/log/net_log.h"
+
+namespace net {
+class FileNetLogObserver;
+}
 
 namespace chromecast {
 
@@ -19,7 +23,7 @@
   ~CastNetLog() override;
 
  private:
-  std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
+  std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(CastNetLog);
 };
diff --git a/chromeos/network/onc/onc_translator_onc_to_shill.cc b/chromeos/network/onc/onc_translator_onc_to_shill.cc
index 53e386d..cc3714d 100644
--- a/chromeos/network/onc/onc_translator_onc_to_shill.cc
+++ b/chromeos/network/onc/onc_translator_onc_to_shill.cc
@@ -156,16 +156,17 @@
   if (user_auth_type == ::onc::openvpn_user_auth_type::kOTP)
     CopyFieldFromONCToShill(::onc::openvpn::kOTP, shill::kOpenVPNTokenProperty);
 
-  // Shill supports only one RemoteCertKU but ONC a list.
-  // Copy only the first entry if existing.
-  const base::ListValue* cert_kus = NULL;
+  // Shill supports only one RemoteCertKU but ONC specifies a list, so copy only
+  // the first entry if the lists exists. Otherwise copy an empty string to
+  // reset any previous configuration.
+  const base::ListValue* cert_kus = nullptr;
   std::string cert_ku;
   if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
-                                               &cert_kus) &&
-      cert_kus->GetString(0, &cert_ku)) {
-    shill_dictionary_->SetStringWithoutPathExpansion(
-        shill::kOpenVPNRemoteCertKUProperty, cert_ku);
+                                               &cert_kus)) {
+    cert_kus->GetString(0, &cert_ku);
   }
+  shill_dictionary_->SetStringWithoutPathExpansion(
+      shill::kOpenVPNRemoteCertKUProperty, cert_ku);
 
   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
        it.Advance()) {
diff --git a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
index a8852a94..f7b3adda 100644
--- a/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
+++ b/chromeos/test/data/network/policy/shill_policy_autoconnect_on_unconfigured_vpn.json
@@ -6,6 +6,7 @@
   "OpenVPN.Password":"some password",
   "OpenVPN.Port":"443",
   "OpenVPN.Proto":"udp",
+  "OpenVPN.RemoteCertKU":"",
   "OpenVPN.User":"abc ${LOGIN_EMAIL} def",
   "Provider.Host":"vpn.my.domain.com",
   "Provider.Type":"openvpn",
diff --git a/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json b/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
index 15470fd6..afe264e 100644
--- a/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
+++ b/chromeos/test/data/network/policy/shill_policy_on_managed_vpn.json
@@ -5,6 +5,7 @@
   "OpenVPN.Password":"some password",
   "OpenVPN.Port":"443",
   "OpenVPN.Proto":"udp",
+  "OpenVPN.RemoteCertKU":"",
   "OpenVPN.User":"abc ${LOGIN_EMAIL} def",
   "Provider.Host":"vpn.my.domain.com",
   "Provider.Type":"openvpn",
diff --git a/chromeos/test/data/network/shill_openvpn_clientcert.json b/chromeos/test/data/network/shill_openvpn_clientcert.json
index 437f0ad..65e9ef9 100644
--- a/chromeos/test/data/network/shill_openvpn_clientcert.json
+++ b/chromeos/test/data/network/shill_openvpn_clientcert.json
@@ -5,6 +5,7 @@
    "OpenVPN.Port": "1234",
    "OpenVPN.Proto": "udp",
    "OpenVPN.User": "hans",
+   "OpenVPN.RemoteCertKU":"",
    "Provider.Host": "terminus.muc",
    "Provider.Type": "openvpn",
    "ProxyConfig": "{\"mode\":\"direct\"}",
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 8024ba4..8f6d89d3 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -224,8 +224,6 @@
       "//components/tracing:unit_tests",
       "//components/translate/content/renderer:unit_tests",
       "//components/visitedlink/test:unit_tests",
-      "//components/viz/host:unit_tests",
-      "//components/viz/service:unit_tests",
       "//components/wallpaper:unit_tests",
       "//components/web_cache/browser:unit_tests",
       "//components/webcrypto:unit_tests",
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
index 28bd0ed..ece02e1 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -53,6 +53,17 @@
     public abstract void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags);
 
     /**
+     * @return whether query autofill suggestion.
+     */
+    // TODO(michaelbai): Change it to abstract after DEP roll.
+    public boolean shouldQueryAutofillSuggestion() {
+        return false;
+    }
+
+    // TODO(michaelbai): Change it to abstract after DEP roll.
+    public void queryAutofillSuggestion() {}
+
+    /**
      * Invoked when filling form is need. AutofillProvider shall ask autofill
      * service for the values with which to fill the form.
      *
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index 1345299..e1dddb6 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -80,7 +80,7 @@
                           return a.type < b.type;
                         }));
   static_assert(kHistogramValue[kNumHistogramValues - 1].type ==
-                    CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE - 1,
+                    CONTENT_SETTINGS_NUM_TYPES - 1,
                 "Update content settings histogram lookup");
 
   const HistogramValue* found = std::lower_bound(
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index 83acdae..272ca9ac 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -71,8 +71,7 @@
   // specific origin.
   CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT,
 
-  // WARNING: This enum is going to be removed soon. Do not depend on NUM_TYPES.
-  CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE,
+  CONTENT_SETTINGS_NUM_TYPES,
 };
 
 struct ContentSettingsTypeHash {
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 230ecf0..4474e321 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1201,13 +1201,17 @@
 action("generate_licenses") {
   _license_path = "$_package_dir/LICENSE"
 
-  script = "//components/cronet/tools/cronet_licenses.py"
+  script = "//tools/licenses.py"
   outputs = [
     _license_path,
   ]
   args = [
-    "license",
+    "license_file",
     rebase_path(_license_path, root_build_dir),
+    "--gn-target",
+    "//components/cronet/android:cronet",
+    "--gn-out-dir",
+    ".",
   ]
 }
 
diff --git a/components/cronet/ios/cronet_environment.h b/components/cronet/ios/cronet_environment.h
index bed027b..31cec890 100644
--- a/components/cronet/ios/cronet_environment.h
+++ b/components/cronet/ios/cronet_environment.h
@@ -29,7 +29,7 @@
 namespace net {
 class CookieStore;
 class NetLog;
-class WriteToFileNetLogObserver;
+class FileNetLogObserver;
 }  // namespace net
 
 namespace cronet {
@@ -131,7 +131,7 @@
                                     const base::Closure& task);
 
   // Helper methods that start/stop net logging on the network thread.
-  void StartNetLogOnNetworkThread(base::ScopedFILE file, bool log_bytes);
+  void StartNetLogOnNetworkThread(const base::FilePath&, bool log_bytes);
   void StopNetLogOnNetworkThread(base::WaitableEvent* log_stopped_event);
 
   // Returns the HttpNetworkSession object from the passed in
@@ -169,7 +169,7 @@
   std::string user_agent_;
   bool user_agent_partial_;
   std::unique_ptr<net::NetLog> net_log_;
-  std::unique_ptr<net::WriteToFileNetLogObserver> net_log_observer_;
+  std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
   bool enable_pkp_bypass_for_local_trust_anchors_;
 
   DISALLOW_COPY_AND_ASSIGN(CronetEnvironment);
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index dd3c96f..609c180 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -8,11 +8,11 @@
 
 #include "base/at_exit.h"
 #include "base/atomicops.h"
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
 #include "base/json/json_writer.h"
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
@@ -37,9 +37,9 @@
 #include "net/http/http_stream_factory.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/http/http_util.h"
+#include "net/log/file_net_log_observer.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_capture_mode.h"
-#include "net/log/write_to_file_net_log_observer.h"
 #include "net/proxy/proxy_service.h"
 #include "net/quic/core/quic_versions.h"
 #include "net/socket/ssl_client_socket.h"
@@ -86,6 +86,10 @@
   DISALLOW_COPY_AND_ASSIGN(CronetURLRequestContextGetter);
 };
 
+void SignalEvent(base::WaitableEvent* event) {
+  event->Signal();
+}
+
 }  // namespace
 
 namespace cronet {
@@ -140,42 +144,34 @@
 
 bool CronetEnvironment::StartNetLog(base::FilePath::StringType file_name,
                                     bool log_bytes) {
-  if (!file_name.length())
+  if (file_name.empty())
     return false;
 
   base::FilePath path(file_name);
 
-  base::ScopedFILE file(base::OpenFile(path, "w"));
-  if (!file) {
-    LOG(ERROR) << "Can not start NetLog to " << path.value() << ": "
-               << strerror(errno);
-    return false;
-  }
-
   LOG(WARNING) << "Starting NetLog to " << path.value();
-  PostToNetworkThread(
-      FROM_HERE,
-      base::Bind(&CronetEnvironment::StartNetLogOnNetworkThread,
-                 base::Unretained(this), base::Passed(&file), log_bytes));
+  PostToNetworkThread(FROM_HERE,
+                      base::Bind(&CronetEnvironment::StartNetLogOnNetworkThread,
+                                 base::Unretained(this), path, log_bytes));
 
   return true;
 }
 
-void CronetEnvironment::StartNetLogOnNetworkThread(base::ScopedFILE file,
+void CronetEnvironment::StartNetLogOnNetworkThread(const base::FilePath& path,
                                                    bool log_bytes) {
   DCHECK(net_log_);
 
-  if (net_log_observer_)
+  if (file_net_log_observer_)
     return;
 
   net::NetLogCaptureMode capture_mode =
       log_bytes ? net::NetLogCaptureMode::IncludeSocketBytes()
                 : net::NetLogCaptureMode::Default();
 
-  net_log_observer_.reset(new net::WriteToFileNetLogObserver());
-  net_log_observer_->set_capture_mode(capture_mode);
-  net_log_observer_->StartObserving(main_context_->net_log(), std::move(file),
-                                    nullptr, main_context_.get());
+  file_net_log_observer_ =
+      net::FileNetLogObserver::CreateUnbounded(path, nullptr);
+  file_net_log_observer_->StartObserving(main_context_->net_log(),
+                                         capture_mode);
   LOG(WARNING) << "Started NetLog";
 }
 
@@ -191,12 +187,12 @@
 
 void CronetEnvironment::StopNetLogOnNetworkThread(
     base::WaitableEvent* log_stopped_event) {
-  if (net_log_observer_) {
+  if (file_net_log_observer_) {
     DLOG(WARNING) << "Stopped NetLog.";
-    net_log_observer_->StopObserving(main_context_.get());
-    net_log_observer_.reset();
+    file_net_log_observer_->StopObserving(
+        nullptr, base::BindOnce(&SignalEvent, log_stopped_event));
+    file_net_log_observer_.reset();
   }
-  log_stopped_event->Signal();
 }
 
 net::HttpNetworkSession* CronetEnvironment::GetHttpNetworkSession(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 7bef41ff..813655b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -257,8 +257,7 @@
     fetcher_callback_.Run(response, status, source->GetResponseCode());
   }
 
-  void CheckIfSecureProxyIsAllowed(const GURL& secure_proxy_check_url,
-                                   FetcherResponseCallback fetcher_callback) {
+  void CheckIfSecureProxyIsAllowed(FetcherResponseCallback fetcher_callback) {
     net::NetworkTrafficAnnotationTag traffic_annotation =
         net::DefineNetworkTrafficAnnotation(
             "data_reduction_proxy_secure_proxy_check", R"(
@@ -283,8 +282,9 @@
                 "it is enabled by installing the Data Saver extension."
               policy_exception_justification: "Not implemented."
             })");
-    fetcher_ = net::URLFetcher::Create(
-        secure_proxy_check_url, net::URLFetcher::GET, this, traffic_annotation);
+    fetcher_ =
+        net::URLFetcher::Create(params::GetSecureProxyCheckURL(),
+                                net::URLFetcher::GET, this, traffic_annotation);
     data_use_measurement::DataUseUserData::AttachToFetcher(
         fetcher_.get(),
         data_use_measurement::DataUseUserData::DATA_REDUCTION_PROXY);
@@ -761,7 +761,6 @@
     // synchronously on the IO thread, and |this| outlives
     // |secure_proxy_checker_|.
     SecureProxyCheck(
-        config_values_->secure_proxy_check_url(),
         base::Bind(&DataReductionProxyConfig::HandleSecureProxyCheckResponse,
                    base::Unretained(this)));
   }
@@ -862,7 +861,6 @@
     // synchronously on the IO thread, and |this| outlives
     // |secure_proxy_checker_|.
     SecureProxyCheck(
-        config_values_->secure_proxy_check_url(),
         base::Bind(&DataReductionProxyConfig::HandleSecureProxyCheckResponse,
                    base::Unretained(this)));
   }
@@ -895,17 +893,15 @@
 }
 
 void DataReductionProxyConfig::SecureProxyCheck(
-    const GURL& secure_proxy_check_url,
     FetcherResponseCallback fetcher_callback) {
   net_log_with_source_ = net::NetLogWithSource::Make(
       net_log_, net::NetLogSourceType::DATA_REDUCTION_PROXY);
   if (event_creator_) {
-    event_creator_->BeginSecureProxyCheck(
-        net_log_with_source_, config_values_->secure_proxy_check_url());
+    event_creator_->BeginSecureProxyCheck(net_log_with_source_,
+                                          params::GetSecureProxyCheckURL());
   }
 
-  secure_proxy_checker_->CheckIfSecureProxyIsAllowed(secure_proxy_check_url,
-                                                     fetcher_callback);
+  secure_proxy_checker_->CheckIfSecureProxyIsAllowed(fetcher_callback);
 }
 
 void DataReductionProxyConfig::FetchWarmupURL() {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index b53ea78..0df055b9 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -28,8 +28,6 @@
 #include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_retry_info.h"
 
-class GURL;
-
 namespace base {
 class SingleThreadTaskRunner;
 }
@@ -266,11 +264,9 @@
   // of either Lo-Fi enabled or Lo-Fi control field trial group.
   void PopulateAutoLoFiParams();
 
-  // Requests the given |secure_proxy_check_url|. Upon completion, returns the
-  // results to the caller via the |fetcher_callback|. Virtualized for unit
-  // testing.
-  virtual void SecureProxyCheck(const GURL& secure_proxy_check_url,
-                                FetcherResponseCallback fetcher_callback);
+  // Requests the secure proxy check URL. Upon completion, returns the results
+  // to the caller via the |fetcher_callback|. Virtualized for unit testing.
+  virtual void SecureProxyCheck(FetcherResponseCallback fetcher_callback);
 
   // Parses the secure proxy check responses and appropriately configures the
   // Data Reduction Proxy rules.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index 5e3b62ca3..c124e62 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -164,9 +164,8 @@
                      bool(const net::URLRequest& request,
                           const net::ProxyConfig& data_reduction_proxy_config,
                           base::TimeDelta* min_retry_delay));
-  MOCK_METHOD2(SecureProxyCheck,
-               void(const GURL& secure_proxy_check_url,
-                    FetcherResponseCallback fetcher_callback));
+  MOCK_METHOD1(SecureProxyCheck,
+               void(FetcherResponseCallback fetcher_callback));
   MOCK_METHOD1(
       IsNetworkQualityProhibitivelySlow,
       bool(const net::NetworkQualityEstimator* network_quality_estimator));
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 8dc44167..6789bb4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -158,9 +158,9 @@
     responder.response = response;
     responder.status = status;
     responder.http_response_code = response_code;
-    EXPECT_CALL(*config(), SecureProxyCheck(_, _))
+    EXPECT_CALL(*config(), SecureProxyCheck(_))
         .Times(1)
-        .WillRepeatedly(testing::WithArgs<1>(
+        .WillRepeatedly(testing::WithArgs<0>(
             testing::Invoke(&responder, &TestResponder::ExecuteCallback)));
     config()->SetIsCaptivePortal(is_captive_portal);
     net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
index 421cca5..4985b9a2 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
@@ -16,7 +16,6 @@
     const DataReductionProxyParams* params) {
   std::unique_ptr<DataReductionProxyMutableConfigValues> config_values(
       new DataReductionProxyMutableConfigValues());
-  config_values->secure_proxy_check_url_ = params->secure_proxy_check_url();
   return config_values;
 }
 
@@ -50,11 +49,6 @@
   return proxies_for_http_;
 }
 
-const GURL& DataReductionProxyMutableConfigValues::secure_proxy_check_url()
-    const {
-  return secure_proxy_check_url_;
-}
-
 void DataReductionProxyMutableConfigValues::UpdateValues(
     const std::vector<DataReductionProxyServer>& proxies_for_http) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
index cc5cfe0..5e97de0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
@@ -42,14 +42,12 @@
   // Overrides of |DataReductionProxyConfigValues|
   const std::vector<DataReductionProxyServer>& proxies_for_http()
       const override;
-  const GURL& secure_proxy_check_url() const override;
 
  protected:
   DataReductionProxyMutableConfigValues();
 
  private:
   std::vector<DataReductionProxyServer> proxies_for_http_;
-  GURL secure_proxy_check_url_;
 
   // Permits use of locally specified Data Reduction Proxy servers instead of
   // ones specified from the Data Saver API.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
index 7ae5f59..008d019 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
@@ -7,8 +7,6 @@
 
 #include <vector>
 
-class GURL;
-
 namespace data_reduction_proxy {
 
 class DataReductionProxyServer;
@@ -20,10 +18,6 @@
   // Returns the HTTP proxy servers to be used.
   virtual const std::vector<DataReductionProxyServer>& proxies_for_http()
       const = 0;
-
-  // Returns the URL to check to decide if the secure proxy origin should be
-  // used.
-  virtual const GURL& secure_proxy_check_url() const = 0;
 };
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 1fe3c78..7b6e0c7 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -32,10 +32,6 @@
 const char kDisabled[] = "Disabled";
 const char kLitePage[] = "Enabled_Preview";
 const char kDefaultSpdyOrigin[] = "https://proxy.googlezip.net:443";
-// A one-off change, until the Data Reduction Proxy configuration service is
-// available.
-const char kCarrierTestOrigin[] =
-    "http://o-o.preferred.nttdocomodcp-hnd1.proxy-dev.googlezip.net:80";
 const char kDefaultFallbackOrigin[] = "compress.googlezip.net:80";
 const char kDefaultSecureProxyCheckUrl[] = "http://check.googlezip.net/connect";
 const char kDefaultWarmupUrl[] = "http://check.googlezip.net/generate_204";
@@ -454,6 +450,16 @@
   return kServerExperimentsFieldTrial;
 }
 
+GURL GetSecureProxyCheckURL() {
+  std::string secure_proxy_check_url =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kDataReductionProxySecureProxyCheckURL);
+  if (secure_proxy_check_url.empty())
+    secure_proxy_check_url = kDefaultSecureProxyCheckUrl;
+
+  return GURL(secure_proxy_check_url);
+}
+
 }  // namespace params
 
 DataReductionProxyTypeInfo::DataReductionProxyTypeInfo() : proxy_index(0) {}
@@ -494,11 +500,6 @@
              << fallback_origin_.ToURI();
     return false;
   }
-
-  if (!secure_proxy_check_url_.is_valid()) {
-    DVLOG(1) << "Invalid secure proxy check url: <null>";
-    return false;
-  }
   return true;
 }
 
@@ -515,10 +516,6 @@
   origin = command_line.GetSwitchValueASCII(switches::kDataReductionProxy);
   std::string fallback_origin =
       command_line.GetSwitchValueASCII(switches::kDataReductionProxyFallback);
-  std::string secure_proxy_check_url = command_line.GetSwitchValueASCII(
-      switches::kDataReductionProxySecureProxyCheckURL);
-  std::string warmup_url = command_line.GetSwitchValueASCII(
-      switches::kDataReductionProxyWarmupURL);
 
   // Set from preprocessor constants those params that are not specified on the
   // command line.
@@ -526,8 +523,6 @@
     origin = GetDefaultOrigin();
   if (fallback_origin.empty())
     fallback_origin = GetDefaultFallbackOrigin();
-  if (secure_proxy_check_url.empty())
-    secure_proxy_check_url = GetDefaultSecureProxyCheckURL();
 
   origin_ = net::ProxyServer::FromURI(origin, net::ProxyServer::SCHEME_HTTP);
   fallback_origin_ =
@@ -542,8 +537,6 @@
     proxies_for_http_.push_back(
         DataReductionProxyServer(fallback_origin_, ProxyServer::CORE));
   }
-
-  secure_proxy_check_url_ = GURL(secure_proxy_check_url);
 }
 
 const std::vector<DataReductionProxyServer>&
@@ -553,18 +546,8 @@
   return proxies_for_http_;
 }
 
-// Returns the URL to check to decide if the secure proxy origin should be
-// used.
-const GURL& DataReductionProxyParams::secure_proxy_check_url() const {
-  return secure_proxy_check_url_;
-}
-
 // TODO(kundaji): Remove tests for macro definitions.
 std::string DataReductionProxyParams::GetDefaultOrigin() const {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kEnableDataReductionProxyCarrierTest))
-    return kCarrierTestOrigin;
   return kDefaultSpdyOrigin;
 }
 
@@ -572,9 +555,4 @@
   return kDefaultFallbackOrigin;
 }
 
-std::string DataReductionProxyParams::GetDefaultSecureProxyCheckURL() const {
-  return kDefaultSecureProxyCheckUrl;
-}
-
-
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index ed5cd10..f65969a 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -170,6 +170,10 @@
 // Returns the name of the server side experiment field trial.
 const char* GetServerExperimentsFieldTrialName();
 
+// Returns the URL to check to decide if the secure proxy origin should be
+// used.
+GURL GetSecureProxyCheckURL();
+
 // Returns true if fetching of the warmup URL is enabled.
 bool FetchWarmupURLEnabled();
 
@@ -209,8 +213,6 @@
   const std::vector<DataReductionProxyServer>& proxies_for_http()
       const override;
 
-  const GURL& secure_proxy_check_url() const override;
-
  protected:
   // Test constructor that optionally won't call Init();
   explicit DataReductionProxyParams(bool should_call_init);
@@ -228,7 +230,6 @@
   // and an empty string otherwise.
   virtual std::string GetDefaultOrigin() const;
   virtual std::string GetDefaultFallbackOrigin() const;
-  virtual std::string GetDefaultSecureProxyCheckURL() const;
 
  private:
   std::vector<DataReductionProxyServer> proxies_for_http_;
@@ -236,8 +237,6 @@
   net::ProxyServer origin_;
   net::ProxyServer fallback_origin_;
 
-  GURL secure_proxy_check_url_;
-
   bool use_override_proxies_for_http_;
   std::vector<DataReductionProxyServer> override_data_reduction_proxy_servers_;
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
index 5b16207..e639988 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
@@ -8,11 +8,9 @@
 // Test values to replace the values specified in preprocessor defines.
 static const char kDefaultOrigin[] = "origin.net:80";
 static const char kDefaultFallbackOrigin[] = "fallback.net:80";
-static const char kDefaultSecureProxyCheckURL[] = "http://proxycheck.net/";
 
 static const char kFlagOrigin[] = "https://origin.org:443";
 static const char kFlagFallbackOrigin[] = "fallback.org:80";
-static const char kFlagSecureProxyCheckURL[] = "http://proxycheck.org/";
 }
 
 namespace data_reduction_proxy {
@@ -38,10 +36,6 @@
   return kDefaultFallbackOrigin;
 }
 
-std::string TestDataReductionProxyParams::DefaultSecureProxyCheckURL() {
-  return kDefaultSecureProxyCheckURL;
-}
-
 std::string TestDataReductionProxyParams::FlagOrigin() {
   return kFlagOrigin;
 }
@@ -50,10 +44,6 @@
   return kFlagFallbackOrigin;
 }
 
-std::string TestDataReductionProxyParams::FlagSecureProxyCheckURL() {
-  return kFlagSecureProxyCheckURL;
-}
-
 std::string TestDataReductionProxyParams::GetDefaultOrigin() const {
   return kDefaultOrigin;
 }
@@ -62,9 +52,4 @@
   return kDefaultFallbackOrigin;
 }
 
-std::string TestDataReductionProxyParams::GetDefaultSecureProxyCheckURL()
-    const {
-  return kDefaultSecureProxyCheckURL;
-}
-
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h
index 201ee9ac..04e5d6e 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h
@@ -23,19 +23,15 @@
   // Test values to replace the values specified in preprocessor defines.
   static std::string DefaultOrigin();
   static std::string DefaultFallbackOrigin();
-  static std::string DefaultSecureProxyCheckURL();
 
   static std::string FlagOrigin();
   static std::string FlagFallbackOrigin();
-  static std::string FlagSecureProxyCheckURL();
 
  protected:
   std::string GetDefaultOrigin() const override;
 
   std::string GetDefaultFallbackOrigin() const override;
 
-  std::string GetDefaultSecureProxyCheckURL() const override;
-
  private:
   bool init_result_;
 };
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index c61a79b..2da780a 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -37,8 +37,7 @@
   }
   void CheckValues(const TestDataReductionProxyParams& params,
                    const std::string& expected_origin,
-                   const std::string& expected_fallback_origin,
-                   const std::string& expected_secure_proxy_check_url) {
+                   const std::string& expected_fallback_origin) {
     std::vector<net::ProxyServer> expected_proxies;
     if (!expected_origin.empty()) {
       expected_proxies.push_back(net::ProxyServer::FromURI(
@@ -53,8 +52,6 @@
     EXPECT_EQ(expected_proxies,
               DataReductionProxyServer::ConvertToNetProxyServers(
                   params.proxies_for_http()));
-    EXPECT_EQ(GURL(expected_secure_proxy_check_url),
-              params.secure_proxy_check_url());
   }
 };
 
@@ -75,8 +72,6 @@
       ProxyServer::CORE));
 
   EXPECT_EQ(expected_proxies, params.proxies_for_http());
-  EXPECT_EQ(GURL(TestDataReductionProxyParams::DefaultSecureProxyCheckURL()),
-            params.secure_proxy_check_url());
 }
 
 TEST_F(DataReductionProxyParamsTest, Flags) {
@@ -86,34 +81,10 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kDataReductionProxyFallback,
       TestDataReductionProxyParams::FlagFallbackOrigin());
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kDataReductionProxySecureProxyCheckURL,
-      TestDataReductionProxyParams::FlagSecureProxyCheckURL());
   TestDataReductionProxyParams params;
   CheckParams(params, true);
   CheckValues(params, TestDataReductionProxyParams::FlagOrigin(),
-              TestDataReductionProxyParams::FlagFallbackOrigin(),
-              TestDataReductionProxyParams::FlagSecureProxyCheckURL());
-}
-
-TEST_F(DataReductionProxyParamsTest, CarrierTestFlag) {
-  static const char kCarrierTestOrigin[] =
-      "http://o-o.preferred.nttdocomodcp-hnd1.proxy-dev.googlezip.net:80";
-  static const char kDefaultFallbackOrigin[] = "compress.googlezip.net:80";
-  base::CommandLine::ForCurrentProcess()->InitFromArgv(0, nullptr);
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kEnableDataReductionProxyCarrierTest, kCarrierTestOrigin);
-  DataReductionProxyParams params;
-  std::vector<DataReductionProxyServer> proxies_for_http;
-  proxies_for_http.push_back(DataReductionProxyServer(
-      net::ProxyServer::FromURI(kCarrierTestOrigin,
-                                net::ProxyServer::SCHEME_HTTP),
-      ProxyServer::CORE));
-  proxies_for_http.push_back(DataReductionProxyServer(
-      net::ProxyServer::FromURI(kDefaultFallbackOrigin,
-                                net::ProxyServer::SCHEME_HTTP),
-      ProxyServer::CORE));
-  EXPECT_EQ(params.proxies_for_http(), proxies_for_http);
+              TestDataReductionProxyParams::FlagFallbackOrigin());
 }
 
 TEST_F(DataReductionProxyParamsTest, AndroidOnePromoFieldTrial) {
@@ -604,6 +575,33 @@
   }
 }
 
+TEST_F(DataReductionProxyParamsTest, SecureProxyURL) {
+  const struct {
+    std::string test_case;
+    std::string flag_value;
+    GURL expected;
+  } tests[] = {
+      {
+          "Nothing set", "", GURL("http://check.googlezip.net/connect"),
+      },
+      {
+          "Only command line set", "http://example.com/flag",
+          GURL("http://example.com/flag"),
+      },
+  };
+
+  for (const auto& test : tests) {
+    // Reset all flags.
+    base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
+    if (!test.flag_value.empty()) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxySecureProxyCheckURL, test.flag_value);
+    }
+    EXPECT_EQ(test.expected, params::GetSecureProxyCheckURL())
+        << test.test_case;
+  }
+}
+
 TEST(DataReductionProxyParamsStandaloneTest, OverrideProxiesForHttp) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kDataReductionProxyHttpProxies,
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index 4877fac..6145b52 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -59,10 +59,6 @@
 const char kDataReductionProxyServerExperimentsDisabled[] =
     "data-reduction-proxy-server-experiments-disabled";
 
-// Sets a URL to fetch to warm up the data reduction proxy on startup and
-// network changes.
-const char kDataReductionProxyWarmupURL[] = "data-reduction-proxy-warmup-url";
-
 // Enable the data reduction proxy.
 const char kEnableDataReductionProxy[] = "enable-spdy-proxy-auth";
 
@@ -70,10 +66,6 @@
 const char kEnableDataReductionProxyBypassWarning[] =
     "enable-data-reduction-proxy-bypass-warning";
 
-// Enables the origin of the carrier test data reduction proxy.
-const char kEnableDataReductionProxyCarrierTest[] =
-    "enable-data-reduction-proxy-carrier-test";
-
 // Enables lite page from the data reduction proxy. This means a lite page
 // should be requested instead of placeholders whenever Lo-Fi mode is on. Lo-fi
 // must also be enabled via a flag or field trial.
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index 0773ba8..7ea15f8 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -26,10 +26,8 @@
 extern const char kDataReductionProxySecureProxyCheckURL[];
 extern const char kDataReductionProxyServerExperimentsDisabled[];
 extern const char kDataReductionProxyServerAlternative[];
-extern const char kDataReductionProxyWarmupURL[];
 extern const char kEnableDataReductionProxy[];
 extern const char kEnableDataReductionProxyBypassWarning[];
-extern const char kEnableDataReductionProxyCarrierTest[];
 extern const char kEnableDataReductionProxyForcePingback[];
 extern const char kEnableDataReductionProxyLitePage[];
 extern const char kEnableDataReductionProxySavingsPromo[];
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 5ca4fee..ddc142a 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -22,6 +22,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h"
 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
@@ -418,16 +419,11 @@
     GrGLTextureInfo texture_info;
     texture_info.fID = buffer->texture->get();
     texture_info.fTarget = GL_TEXTURE_2D;
-    GrBackendTextureDesc desc;
-    desc.fFlags = kRenderTarget_GrBackendTextureFlag;
-    desc.fWidth = width_;
-    desc.fHeight = height_;
-    desc.fConfig = kGrPixelConfig;
-    desc.fOrigin = kTopLeft_GrSurfaceOrigin;
-    desc.fTextureHandle = reinterpret_cast<GrBackendObject>(&texture_info);
-
+    GrBackendTexture backend_texture(width_, height_, kGrPixelConfig,
+                                     texture_info);
     buffer->sk_surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
-        gr_context_.get(), desc, nullptr);
+        gr_context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
+        /* sampleCnt */ 0, /* colorSpace */ nullptr, /* props */ nullptr);
     DCHECK(buffer->sk_surface);
     return buffer;
   }
diff --git a/components/handoff/handoff_manager.h b/components/handoff/handoff_manager.h
index fedaf9b9..9293ccf 100644
--- a/components/handoff/handoff_manager.h
+++ b/components/handoff/handoff_manager.h
@@ -31,12 +31,15 @@
 // The active URL is defined as the URL of the most recently accessed tab. This
 // method should be called any time the active URL might have changed. This
 // method is idempotent.
-- (void)updateActiveURL:(const GURL&)url;
+- (void)updateActiveURL:(const GURL&)url
+    __attribute__((availability(macos, introduced = 10.10)));
 
 @end
 
+#if defined(OS_IOS)
 @interface HandoffManager (TestingOnly)
 - (NSURL*)userActivityWebpageURL;
 @end
+#endif
 
 #endif  // COMPONENTS_HANDOFF_HANDOFF_MANAGER_H_
diff --git a/components/handoff/handoff_manager.mm b/components/handoff/handoff_manager.mm
index 420eca0..366a80d 100644
--- a/components/handoff/handoff_manager.mm
+++ b/components/handoff/handoff_manager.mm
@@ -23,20 +23,23 @@
 @interface HandoffManager ()
 
 // The active user activity.
-@property(nonatomic, retain) NSUserActivity* userActivity;
+@property(nonatomic, retain) NSUserActivity* userActivity
+    __attribute__((availability(macos, introduced=10.10)));
 
 // Whether the URL of the current tab should be exposed for Handoff.
 - (BOOL)shouldUseActiveURL;
 
 // Updates the active NSUserActivity.
-- (void)updateUserActivity;
+- (void)updateUserActivity
+    __attribute__((availability(macos, introduced = 10.10)));
 
 @end
 
 @implementation HandoffManager {
   base::mac::ObjCPropertyReleaser _propertyReleaser_HandoffManager;
   GURL _activeURL;
-  NSUserActivity* _userActivity;
+  NSUserActivity* _userActivity
+      __attribute__((availability(macos, introduced = 10.10)));
   handoff::Origin _origin;
 }
 
@@ -95,11 +98,8 @@
   // Invalidate the old user activity and make a new one.
   [self.userActivity invalidate];
 
-  Class aClass = NSClassFromString(@"NSUserActivity");
-  base::scoped_nsobject<NSUserActivity> userActivity(
-      [[aClass performSelector:@selector(alloc)]
-          performSelector:@selector(initWithActivityType:)
-               withObject:handoff::kChromeHandoffActivityType]);
+  base::scoped_nsobject<NSUserActivity> userActivity([[NSUserActivity alloc]
+      initWithActivityType:handoff::kChromeHandoffActivityType]);
   self.userActivity = userActivity;
   self.userActivity.webpageURL = net::NSURLWithGURL(_activeURL);
   NSString* origin = handoff::StringFromOrigin(_origin);
@@ -110,6 +110,7 @@
 
 @end
 
+#if defined(OS_IOS)
 @implementation HandoffManager (TestingOnly)
 
 - (NSURL*)userActivityWebpageURL {
@@ -117,3 +118,4 @@
 }
 
 @end
+#endif
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 9dae595..050068e 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -198,11 +198,6 @@
       GetVariationParam(quic_trial_params, "race_cert_verification"), "true");
 }
 
-bool ShouldQuicDoNotFragment(const VariationParameters& quic_trial_params) {
-  return base::LowerCaseEqualsASCII(
-      GetVariationParam(quic_trial_params, "do_not_fragment"), "true");
-}
-
 bool ShouldQuicEstimateInitialRtt(
     const VariationParameters& quic_trial_params) {
   return base::LowerCaseEqualsASCII(
@@ -294,7 +289,6 @@
     }
     params->quic_race_cert_verification =
         ShouldQuicRaceCertVerification(quic_trial_params);
-    params->quic_do_not_fragment = ShouldQuicDoNotFragment(quic_trial_params);
     params->quic_estimate_initial_rtt =
         ShouldQuicEstimateInitialRtt(quic_trial_params);
     params->quic_migrate_sessions_on_network_change =
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index 5b18958..94e81d0 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -90,7 +90,6 @@
   EXPECT_EQ(net::kQuicYieldAfterDurationMilliseconds,
             params_.quic_packet_reader_yield_after_duration_milliseconds);
   EXPECT_FALSE(params_.quic_race_cert_verification);
-  EXPECT_FALSE(params_.quic_do_not_fragment);
   EXPECT_FALSE(params_.quic_estimate_initial_rtt);
   EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change);
   EXPECT_FALSE(params_.quic_migrate_sessions_early);
@@ -234,17 +233,6 @@
   EXPECT_TRUE(params_.enable_server_push_cancellation);
 }
 
-TEST_F(NetworkSessionConfiguratorTest, QuicDoNotFragment) {
-  std::map<std::string, std::string> field_trial_params;
-  field_trial_params["do_not_fragment"] = "true";
-  variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
-  base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
-  ParseFieldTrials();
-
-  EXPECT_TRUE(params_.quic_do_not_fragment);
-}
-
 TEST_F(NetworkSessionConfiguratorTest, QuicEstimateInitialRtt) {
   std::map<std::string, std::string> field_trial_params;
   field_trial_params["estimate_initial_rtt"] = "true";
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index 1339cc1..aced3bb3 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -432,19 +432,27 @@
 }
 
 void ContentSuggestionsService::SetRemoteSuggestionsEnabled(bool enabled) {
-  pref_service_->SetBoolean(prefs::kEnableSnippets, enabled);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsEnabled() const {
-  return pref_service_->GetBoolean(prefs::kEnableSnippets);
+  return !remote_suggestions_provider_->IsDisabled();
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsManaged() const {
-  return pref_service_->IsManagedPreference(prefs::kEnableSnippets);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
+  return false;
 }
 
 bool ContentSuggestionsService::AreRemoteSuggestionsManagedByCustodian() const {
-  return pref_service_->IsPreferenceManagedByCustodian(prefs::kEnableSnippets);
+  // TODO(dgn): Rewire if we decide to implement a dedicated prefs page. If not
+  // remove by M62.
+  NOTREACHED();
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider.h b/components/ntp_snippets/remote/remote_suggestions_provider.h
index 5e94b8a..a2b76f5 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider.h
@@ -41,6 +41,9 @@
   virtual GURL GetUrlWithFavicon(
       const ContentSuggestion::ID& suggestion_id) const = 0;
 
+  // Whether the service is explicity disabled.
+  virtual bool IsDisabled() const = 0;
+
  protected:
   RemoteSuggestionsProvider(Observer* observer);
 };
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index 877d27d..c13ee94 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -348,6 +348,10 @@
   return ContentSuggestion::GetFaviconDomain(suggestion->url());
 }
 
+bool RemoteSuggestionsProviderImpl::IsDisabled() const {
+  return state_ == State::DISABLED;
+}
+
 void RemoteSuggestionsProviderImpl::FetchSuggestions(
     bool interactive_request,
     const FetchStatusCallback& callback) {
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index 1941a49c..ef70fc4 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -94,6 +94,8 @@
   GURL GetUrlWithFavicon(
       const ContentSuggestion::ID& suggestion_id) const override;
 
+  bool IsDisabled() const override;
+
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
index 715bfb3..e59eb4a 100644
--- a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -81,6 +81,7 @@
                      const RemoteSuggestionsFetcher*());
   MOCK_CONST_METHOD1(GetUrlWithFavicon,
                      GURL(const ContentSuggestion::ID& suggestion_id));
+  MOCK_CONST_METHOD0(IsDisabled, bool());
   MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
   MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
   MOCK_METHOD3(ClearHistory,
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index ed4e99b..38fc464 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -14,6 +14,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/google/core/browser/google_util.h"
 #include "components/ntp_tiles/constants.h"
diff --git a/components/ntp_tiles/popular_sites_impl_unittest.cc b/components/ntp_tiles/popular_sites_impl_unittest.cc
index 419483e..d29217f2 100644
--- a/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/ntp_tiles/constants.h"
 #include "components/ntp_tiles/json_unsafe_parser.h"
 #include "components/ntp_tiles/pref_names.h"
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index ffbd5c72..cc0aba25 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -212,6 +212,9 @@
   // Gets the formatting flags used for display of suggestions. This method
   // encapsulates the return of experimental flags too, so any URLs displayed
   // as an Omnibox suggestion should use this method.
+  //
+  // This function returns flags that may destructively format the URL, and
+  // therefore should never be used for the |fill_into_edit| field.
   static url_formatter::FormatUrlTypes GetFormatTypes(bool trim_scheme);
 
   // Computes the stripped destination URL (via GURLToStrippedGURL()) and
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc
index 2691564d..023a2af 100644
--- a/components/omnibox/browser/history_url_provider.cc
+++ b/components/omnibox/browser/history_url_provider.cc
@@ -571,10 +571,10 @@
     // Trim off "http://" if the user didn't type it.
     DCHECK(!trim_http ||
            !AutocompleteInput::HasHTTPScheme(input.text()));
-    auto format_types = AutocompleteMatch::GetFormatTypes(false);
     base::string16 display_string(url_formatter::FormatUrl(
-        destination_url, format_types, net::UnescapeRule::SPACES, nullptr,
-        nullptr, nullptr));
+        destination_url,
+        url_formatter::kFormatUrlOmitAll & ~url_formatter::kFormatUrlOmitHTTP,
+        net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
     const size_t offset = trim_http ? TrimHttpPrefix(&display_string) : 0;
     match.fill_into_edit =
         AutocompleteInput::FormattedStringWithEquivalentMeaning(
@@ -1143,11 +1143,9 @@
   size_t inline_autocomplete_offset =
       history_match.input_location + params.input.text().length();
 
-  auto format_types = AutocompleteMatch::GetFormatTypes(
-      params.trim_http && !history_match.match_in_scheme);
-  // Never omit HTTPS from fill_into_edit lest it be misinterpreted.
-  auto fill_into_edit_format_types =
-      format_types & ~url_formatter::kFormatUrlExperimentalOmitHTTPS;
+  auto fill_into_edit_format_types = url_formatter::kFormatUrlOmitAll;
+  if (!params.trim_http || history_match.match_in_scheme)
+    fill_into_edit_format_types &= ~url_formatter::kFormatUrlOmitHTTP;
   match.fill_into_edit =
       AutocompleteInput::FormattedStringWithEquivalentMeaning(
           info.url(),
@@ -1175,6 +1173,8 @@
        (inline_autocomplete_offset >= match.fill_into_edit.length()));
 
   size_t match_start = history_match.input_location;
+  const auto format_types = AutocompleteMatch::GetFormatTypes(
+      params.trim_http && !history_match.match_in_scheme);
   match.contents = url_formatter::FormatUrl(info.url(), format_types,
                                             net::UnescapeRule::SPACES, nullptr,
                                             nullptr, &match_start);
diff --git a/components/omnibox/browser/physical_web_provider.cc b/components/omnibox/browser/physical_web_provider.cc
index f0033f43..35a3c4d6 100644
--- a/components/omnibox/browser/physical_web_provider.cc
+++ b/components/omnibox/browser/physical_web_provider.cc
@@ -233,10 +233,8 @@
         AutocompleteMatchType::PHYSICAL_WEB);
     match.destination_url = url;
 
-    // Physical Web results should omit http:// (but not https://) and never
-    // appear bold.
-    match.contents = url_formatter::FormatUrl(url,
-        url_formatter::kFormatUrlOmitHTTP, net::UnescapeRule::SPACES,
+    match.contents = url_formatter::FormatUrl(
+        url, AutocompleteMatch::GetFormatTypes(true), net::UnescapeRule::SPACES,
         nullptr, nullptr, nullptr);
     match.contents_class.push_back(
         ACMatchClassification(0, ACMatchClassification::URL));
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc
index f0424978..bddf2ea94 100644
--- a/components/omnibox/browser/scored_history_match.cc
+++ b/components/omnibox/browser/scored_history_match.cc
@@ -15,7 +15,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_offset_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/omnibox/browser/history_url_provider.h"
@@ -102,6 +101,17 @@
   }
 }
 
+size_t GetAdjustedOffsetForComponent(
+    const GURL& url,
+    const base::OffsetAdjuster::Adjustments& adjustments,
+    const url::Parsed::ComponentType& component) {
+  const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
+
+  size_t result = parsed.CountCharactersBefore(component, true);
+  base::OffsetAdjuster::AdjustOffset(adjustments, &result);
+  return result;
+}
+
 }  // namespace
 
 // static
@@ -254,8 +264,9 @@
     }
   }
 
-  const float topicality_score = GetTopicalityScore(
-      terms_vector.size(), url, terms_to_word_starts_offsets, word_starts);
+  const float topicality_score =
+      GetTopicalityScore(terms_vector.size(), gurl, adjustments,
+                         terms_to_word_starts_offsets, word_starts);
   const float frequency_score = GetFrequency(now, is_url_bookmarked, visits);
   const float specificity_score =
       GetDocumentSpecificityScore(num_matching_pages);
@@ -425,7 +436,8 @@
 
 float ScoredHistoryMatch::GetTopicalityScore(
     const int num_terms,
-    const base::string16& url,
+    const GURL& url,
+    const base::OffsetAdjuster::Adjustments& adjustments,
     const WordStarts& terms_to_word_starts_offsets,
     const RowWordStarts& word_starts) {
   // A vector that accumulates per-term scores.  The strongest match--a
@@ -439,32 +451,24 @@
       word_starts.url_word_starts_.begin();
   WordStarts::const_iterator end_word_starts =
       word_starts.url_word_starts_.end();
-  const size_t question_mark_pos = url.find('?');
-  const size_t colon_pos = url.find(':');
-  // The + 3 skips the // that probably appears in the protocol
-  // after the colon.  If the protocol doesn't have two slashes after
-  // the colon, that's okay--all this ends up doing is starting our
-  // search for the next / a few characters into the hostname.  The
-  // only times this can cause problems is if we have a protocol without
-  // a // after the colon and the hostname is only one or two characters.
-  // This isn't worth worrying about.
-  const size_t end_of_hostname_pos = (colon_pos != std::string::npos)
-                                         ? url.find('/', colon_pos + 3)
-                                         : url.find('/');
-  size_t last_part_of_hostname_pos = (end_of_hostname_pos != std::string::npos)
-                                         ? url.rfind('.', end_of_hostname_pos)
-                                         : url.rfind('.');
+
+  const size_t query_pos =
+      GetAdjustedOffsetForComponent(url, adjustments, url::Parsed::QUERY);
+  const size_t host_pos =
+      GetAdjustedOffsetForComponent(url, adjustments, url::Parsed::HOST);
+  const size_t path_pos =
+      GetAdjustedOffsetForComponent(url, adjustments, url::Parsed::PATH);
   // Loop through all URL matches and score them appropriately.
   // First, filter all matches not at a word boundary and in the path (or
   // later).
   url_matches = FilterTermMatchesByWordStarts(
       url_matches, terms_to_word_starts_offsets, word_starts.url_word_starts_,
-      end_of_hostname_pos, std::string::npos);
-  if (colon_pos != std::string::npos) {
+      path_pos, std::string::npos);
+  if (url.has_scheme()) {
     // Also filter matches not at a word boundary and in the scheme.
     url_matches = FilterTermMatchesByWordStarts(
         url_matches, terms_to_word_starts_offsets, word_starts.url_word_starts_,
-        0, colon_pos);
+        0, host_pos);
   }
   for (const auto& url_match : url_matches) {
     // Calculate the offset in the URL string where the meaningful (word) part
@@ -480,21 +484,22 @@
     }
     const bool at_word_boundary = (next_word_starts != end_word_starts) &&
                                   (*next_word_starts == term_word_offset);
-    if ((question_mark_pos != std::string::npos) &&
-        (term_word_offset >= question_mark_pos)) {
-      // The match is in a CGI ?... fragment.
+    if (term_word_offset >= query_pos) {
+      // The match is in the query or ref component.
       DCHECK(at_word_boundary);
       term_scores[url_match.term_num] += 5;
-    } else if ((end_of_hostname_pos != std::string::npos) &&
-               (term_word_offset >= end_of_hostname_pos)) {
-      // The match is in the path.
+    } else if (term_word_offset >= path_pos) {
+      // The match is in the path component.
       DCHECK(at_word_boundary);
       term_scores[url_match.term_num] += 8;
-    } else if ((colon_pos == std::string::npos) ||
-               (term_word_offset >= colon_pos)) {
-      // The match is in the hostname.
-      if ((last_part_of_hostname_pos == std::string::npos) ||
-          (term_word_offset < last_part_of_hostname_pos)) {
+    } else if (term_word_offset >= host_pos) {
+      // Get the position of the last period in the hostname.
+      const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
+      size_t last_part_of_host_pos = url.possibly_invalid_spec().rfind(
+          '.', parsed.CountCharactersBefore(url::Parsed::PATH, true));
+      base::OffsetAdjuster::AdjustOffset(adjustments, &last_part_of_host_pos);
+
+      if (term_word_offset < last_part_of_host_pos) {
         // Either there are no dots in the hostname or this match isn't
         // the last dotted component.
         term_scores[url_match.term_num] += at_word_boundary ? 10 : 2;
diff --git a/components/omnibox/browser/scored_history_match.h b/components/omnibox/browser/scored_history_match.h
index f9c432a..ab700643 100644
--- a/components/omnibox/browser/scored_history_match.h
+++ b/components/omnibox/browser/scored_history_match.h
@@ -12,6 +12,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
+#include "base/strings/utf_offset_string_conversions.h"
 #include "base/time/time.h"
 #include "components/history/core/browser/history_match.h"
 #include "components/history/core/browser/history_types.h"
@@ -122,9 +123,10 @@
   // url_matches and title_matches in the process so they only reflect matches
   // used for scoring.  (For instance, some mid-word matches are not given
   // credit in scoring.)  Requires that |url_matches| and |title_matches| are
-  // sorted.
+  // sorted. |adjustments| must contain any adjustments used to format |url|.
   float GetTopicalityScore(const int num_terms,
-                           const base::string16& cleaned_up_url,
+                           const GURL& url,
+                           const base::OffsetAdjuster::Adjustments& adjustments,
                            const WordStarts& terms_to_word_starts_offsets,
                            const RowWordStarts& word_starts);
 
diff --git a/components/omnibox/browser/scored_history_match_unittest.cc b/components/omnibox/browser/scored_history_match_unittest.cc
index f3fb2fa..70bc2ac 100644
--- a/components/omnibox/browser/scored_history_match_unittest.cc
+++ b/components/omnibox/browser/scored_history_match_unittest.cc
@@ -66,7 +66,7 @@
   // GetTopicalityScore().  It only works for scoring a single term, not
   // multiple terms.
   float GetTopicalityScoreOfTermAgainstURLAndTitle(const base::string16& term,
-                                                   const base::string16& url,
+                                                   const GURL& url,
                                                    const base::string16& title);
 };
 
@@ -107,7 +107,7 @@
 
 float ScoredHistoryMatchTest::GetTopicalityScoreOfTermAgainstURLAndTitle(
     const base::string16& term,
-    const base::string16& url,
+    const GURL& url,
     const base::string16& title) {
   String16Vector term_vector = {term};
   WordStarts term_word_starts = {0};
@@ -119,16 +119,18 @@
     term_word_starts[0] = iter.prev();
   }
   RowWordStarts row_word_starts;
-  String16SetFromString16(url, &row_word_starts.url_word_starts_);
+  base::string16 url_string = base::UTF8ToUTF16(url.spec());
+  String16SetFromString16(url_string, &row_word_starts.url_word_starts_);
   String16SetFromString16(title, &row_word_starts.title_word_starts_);
   ScoredHistoryMatch scored_match(history::URLRow(GURL(url)), VisitInfoVector(),
                                   term, term_vector, term_word_starts,
                                   row_word_starts, false, 1, base::Time::Max());
-  scored_match.url_matches = MatchTermInString(term, url, 0);
+  scored_match.url_matches = MatchTermInString(term, url_string, 0);
   scored_match.title_matches = MatchTermInString(term, title, 0);
   scored_match.topicality_threshold_ = -1;
-  return scored_match.GetTopicalityScore(1, url, term_word_starts,
-                                         row_word_starts);
+  return scored_match.GetTopicalityScore(1, url,
+                                         base::OffsetAdjuster::Adjustments(),
+                                         term_word_starts, row_word_starts);
 }
 
 TEST_F(ScoredHistoryMatchTest, Scoring) {
@@ -350,10 +352,10 @@
 
 TEST_F(ScoredHistoryMatchTest, GetTopicalityScoreTrailingSlash) {
   const float hostname = GetTopicalityScoreOfTermAgainstURLAndTitle(
-      ASCIIToUTF16("def"), ASCIIToUTF16("http://abc.def.com/"),
+      ASCIIToUTF16("def"), GURL("http://abc.def.com/"),
       ASCIIToUTF16("Non-Matching Title"));
   const float hostname_no_slash = GetTopicalityScoreOfTermAgainstURLAndTitle(
-      ASCIIToUTF16("def"), ASCIIToUTF16("http://abc.def.com"),
+      ASCIIToUTF16("def"), GURL("http://abc.def.com"),
       ASCIIToUTF16("Non-Matching Title"));
   EXPECT_EQ(hostname_no_slash, hostname);
 }
@@ -615,9 +617,7 @@
 // This function only tests scoring of single terms that match exactly
 // once somewhere in the URL or title.
 TEST_F(ScoredHistoryMatchTest, GetTopicalityScore) {
-  base::string16 url = ASCIIToUTF16(
-      "http://abc.def.com/path1/path2?"
-      "arg1=val1&arg2=val2#hash_component");
+  GURL url("http://abc.def.com/path1/path2?arg1=val1&arg2=val2#hash_component");
   base::string16 title = ASCIIToUTF16("here is a title");
   auto Score = [&](const char* term) {
     return GetTopicalityScoreOfTermAgainstURLAndTitle(ASCIIToUTF16(term), url,
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc
index 11ac6b3..941fc4a 100644
--- a/components/omnibox/browser/search_suggestion_parser.cc
+++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -279,13 +279,9 @@
       formatted_url_.find(input_text) : prefix->prefix.length();
   bool trim_http = !AutocompleteInput::HasHTTPScheme(input_text) &&
                    (!prefix || (match_start != 0));
-  const url_formatter::FormatUrlTypes format_types =
-      url_formatter::kFormatUrlOmitAll &
-      ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP);
-
   base::string16 match_contents = url_formatter::FormatUrl(
-      url_, format_types, net::UnescapeRule::SPACES, nullptr,
-      nullptr, &match_start);
+      url_, AutocompleteMatch::GetFormatTypes(trim_http),
+      net::UnescapeRule::SPACES, nullptr, nullptr, &match_start);
   // If the first match in the untrimmed string was inside a scheme that we
   // trimmed, look for a subsequent match.
   if (match_start == base::string16::npos)
diff --git a/components/payments/core/subkey_requester.cc b/components/payments/core/subkey_requester.cc
index 513fc54..f4dfbc8 100644
--- a/components/payments/core/subkey_requester.cc
+++ b/components/payments/core/subkey_requester.cc
@@ -29,10 +29,12 @@
  public:
   // The |delegate| and |address_validator| need to outlive this Request.
   SubKeyRequest(const std::string& region_code,
+                const std::string& language,
                 int timeout_seconds,
                 autofill::AddressValidator* address_validator,
                 SubKeyReceiverCallback on_subkeys_received)
       : region_code_(region_code),
+        language_(language),
         address_validator_(address_validator),
         on_subkeys_received_(std::move(on_subkeys_received)),
         has_responded_(false),
@@ -52,12 +54,20 @@
       return;
     has_responded_ = true;
 
-    std::move(on_subkeys_received_)
-        .Run(address_validator_->GetRegionSubKeys(region_code_));
+    auto subkeys =
+        address_validator_->GetRegionSubKeys(region_code_, language_);
+    std::vector<std::string> subkeys_codes;
+    std::vector<std::string> subkeys_names;
+    for (auto s : subkeys) {
+      subkeys_codes.push_back(s.first);
+      subkeys_names.push_back(s.second);
+    }
+    std::move(on_subkeys_received_).Run(subkeys_codes, subkeys_names);
   }
 
  private:
   std::string region_code_;
+  std::string language_;
   // Not owned. Never null. Outlive this object.
   autofill::AddressValidator* address_validator_;
 
@@ -78,12 +88,14 @@
 SubKeyRequester::~SubKeyRequester() {}
 
 void SubKeyRequester::StartRegionSubKeysRequest(const std::string& region_code,
+                                                const std::string& language,
                                                 int timeout_seconds,
                                                 SubKeyReceiverCallback cb) {
   DCHECK(timeout_seconds >= 0);
 
-  std::unique_ptr<SubKeyRequest> request(base::MakeUnique<SubKeyRequest>(
-      region_code, timeout_seconds, &address_validator_, std::move(cb)));
+  std::unique_ptr<SubKeyRequest> request(
+      base::MakeUnique<SubKeyRequest>(region_code, language, timeout_seconds,
+                                      &address_validator_, std::move(cb)));
 
   if (AreRulesLoadedForRegion(region_code)) {
     request->OnRulesLoaded();
diff --git a/components/payments/core/subkey_requester.h b/components/payments/core/subkey_requester.h
index 1813781d..a7d597f 100644
--- a/components/payments/core/subkey_requester.h
+++ b/components/payments/core/subkey_requester.h
@@ -10,8 +10,10 @@
 
 namespace payments {
 
+// This receives a region code and the device's language.
 using SubKeyReceiverCallback =
-    base::OnceCallback<void(const std::vector<std::string>&)>;
+    base::OnceCallback<void(const std::vector<std::string>&,
+                            const std::vector<std::string>&)>;
 
 // SubKeyRequester Loads Rules from the server and extracts the subkeys.
 // For a given key (region code for a country, such as US), the list of its
@@ -37,8 +39,9 @@
   // |region_code|. The received subkeys will be returned to the |requester|. If
   // the subkeys are not received in |timeout_seconds|, then the requester will
   // be informed and the request will be canceled. |requester| should never be
-  // null.
+  // null. The requesting device language is set to |language|, ex:"fr".
   void StartRegionSubKeysRequest(const std::string& region_code,
+                                 const std::string& language,
                                  int timeout_seconds,
                                  SubKeyReceiverCallback cb);
 
diff --git a/components/payments/core/subkey_requester_unittest.cc b/components/payments/core/subkey_requester_unittest.cc
index f679c16..474700c 100644
--- a/components/payments/core/subkey_requester_unittest.cc
+++ b/components/payments/core/subkey_requester_unittest.cc
@@ -25,6 +25,7 @@
 using ::i18n::addressinput::TestdataSource;
 
 const char kLocale[] = "OZ";
+const char kLanguage[] = "en";
 const int kInvalidSize = -1;
 const int kCorrectSize = 2;  // for subkeys = Do, Re
 const int kEmptySize = 0;
@@ -33,8 +34,9 @@
  public:
   SubKeyReceiver() : subkeys_size_(kInvalidSize) {}
 
-  void OnSubKeysReceived(const std::vector<std::string>& subkeys) {
-    subkeys_size_ = subkeys.size();
+  void OnSubKeysReceived(const std::vector<std::string>& subkeys_codes,
+                         const std::vector<std::string>& subkeys_names) {
+    subkeys_size_ = subkeys_codes.size();
   }
 
   int subkeys_size() const { return subkeys_size_; }
@@ -62,7 +64,13 @@
         new std::string(
             "{\"data/OZ\": "
             "{\"id\":\"data/OZ\",\"key\":\"OZ\",\"name\":\"Oz \", "
-            "\"lang\":\"en\",\"languages\":\"en\",\"sub_keys\":\"DO~Re\"}}"));
+            "\"lang\":\"en\",\"sub_keys\":\"DO~RE\", \"sub_names\":\"Do~Re\"},"
+            "\"data/OZ/DO\": "
+            "{\"id\":\"data/OZ/DO\",\"key\":\"DO\",\"name\":\"Do \", "
+            "\"lang\":\"en\"},"
+            "\"data/OZ/RE\": "
+            "{\"id\":\"data/OZ/RE\",\"key\":\"RE\",\"name\":\"Re \", "
+            "\"lang\":\"en\"}}"));
   }
 
  private:
@@ -138,7 +146,7 @@
   EXPECT_TRUE(requester_->AreRulesLoadedForRegion(kLocale));
 
   // Start the request.
-  requester_->StartRegionSubKeysRequest(kLocale, 0, std::move(cb));
+  requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb));
 
   // Since the rules are already loaded, the subkeys should be received
   // synchronously.
@@ -159,7 +167,7 @@
   requester_->ShouldLoadRules(false);
 
   // Start the normalization.
-  requester_->StartRegionSubKeysRequest(kLocale, 0, std::move(cb));
+  requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb));
 
   // Let the timeout execute.
   base::RunLoop().RunUntilIdle();
@@ -181,7 +189,7 @@
   // call.
   requester_->ShouldLoadRules(true);
   // Start the request.
-  requester_->StartRegionSubKeysRequest(kLocale, 0, std::move(cb));
+  requester_->StartRegionSubKeysRequest(kLocale, kLanguage, 0, std::move(cb));
 
   // Even if the rules are not loaded before the call to
   // StartRegionSubKeysRequest, they should get loaded in the call. Since our
diff --git a/components/resources/safe_browsing_resources.grdp b/components/resources/safe_browsing_resources.grdp
index ae40ba6..1b2d2115 100644
--- a/components/resources/safe_browsing_resources.grdp
+++ b/components/resources/safe_browsing_resources.grdp
@@ -2,4 +2,5 @@
 <grit-part>
   <include name="IDR_SAFE_BROWSING_HTML" file="..\..\components\safe_browsing\web_ui\resources\safe_browsing.html" type="BINDATA" />
   <include name="IDR_SAFE_BROWSING_CSS" file="..\..\components\safe_browsing\web_ui\resources\safe_browsing.css" type="BINDATA" />
+  <include name="IDR_SAFE_BROWSING_JS" file="..\..\components\safe_browsing\web_ui\resources\safe_browsing.js" type="BINDATA" />
 </grit-part>
diff --git a/components/safe_browsing/BUILD.gn b/components/safe_browsing/BUILD.gn
index 0f05c746..7b090bc 100644
--- a/components/safe_browsing/BUILD.gn
+++ b/components/safe_browsing/BUILD.gn
@@ -24,6 +24,7 @@
   ]
   deps = [
     ":base_ping_manager",
+    ":features",
     "//base:base",
     "//base:i18n",
     "//components/safe_browsing/common:safe_browsing_prefs",
@@ -69,3 +70,14 @@
     "//testing/gtest",
   ]
 }
+
+static_library("features") {
+  sources = [
+    "features.cc",
+    "features.h",
+  ]
+
+  deps = [
+    "//base:base",
+  ]
+}
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
new file mode 100644
index 0000000..20a49b1
--- /dev/null
+++ b/components/safe_browsing/features.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/features.h"
+
+#include <stddef.h>
+#include <algorithm>
+#include <utility>
+#include <vector>
+#include "base/feature_list.h"
+
+#include "base/macros.h"
+#include "base/values.h"
+namespace safe_browsing {
+// Please define any new SafeBrowsing related features in this file, and add
+// them to  the ExperimentalFeaturesList below to start displaying their status
+// on the  chrome://safe-browsing page.
+const base::Feature kLocalDatabaseManagerEnabled{
+    "SafeBrowsingV4LocalDatabaseManagerEnabled",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kV4OnlyEnabled{"SafeBrowsingV4OnlyEnabled",
+                                   base::FEATURE_DISABLED_BY_DEFAULT};
+// This Feature specifies which non-resource HTML Elements to collect based on
+// their tag and attributes. It's a single param containing a comma-separated
+// list of pairs. For example: "tag1,id,tag1,height,tag2,foo" - this will
+// collect elements with tag "tag1" that have attribute "id" or "height" set,
+// and elements of tag "tag2" if they have attribute "foo" set. All tag names
+// and attributes should be lower case.
+const base::Feature kThreatDomDetailsTagAndAttributeFeature{
+    "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
+
+namespace {
+// List of experimental features. Boolean value for each list member should be
+// set to True if the experiment is currently running at a probability other
+// than 1 or 0, or to False otherwise.
+std::vector<std::pair<const base::Feature*, bool>> ExperimentalFeaturesList = {
+    std::make_pair(&kLocalDatabaseManagerEnabled, true),
+    std::make_pair(&kV4OnlyEnabled, true),
+    std::make_pair(&kThreatDomDetailsTagAndAttributeFeature, true)};
+
+// Adds the name and the enabled/disabled status of a given feature.
+void AddFeatureAndAvailability(const base::Feature* expFeature,
+                               base::ListValue* paramList) {
+  paramList->GetList().push_back(base::Value(expFeature->name));
+  if (base::FeatureList::IsEnabled(*expFeature)) {
+    paramList->GetList().push_back(base::Value("Enabled"));
+  } else {
+    paramList->GetList().push_back(base::Value("Disabled"));
+  }
+}
+}  // namespace
+// Returns the list of the experimental features that are enabled or disabled,
+// as part of currently running Safe Browsing experiments.
+base::ListValue GetFeatureStatusList() {
+  base::ListValue paramList;
+  for (std::vector<std::pair<const base::Feature*, bool>>::iterator it =
+           ExperimentalFeaturesList.begin();
+       it != ExperimentalFeaturesList.end(); ++it) {
+    if ((*it).second) {
+      AddFeatureAndAvailability((*it).first, &paramList);
+    }
+  }
+  return paramList;
+}
+
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
new file mode 100644
index 0000000..c4a0a12
--- /dev/null
+++ b/components/safe_browsing/features.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SAFE_BROWSING_FEATURES_H_
+#define COMPONENTS_SAFE_BROWSING_FEATURES_H_
+
+#include <stddef.h>
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/values.h"
+namespace base {
+class ListValue;
+}  // namespace base
+
+namespace safe_browsing {
+// Features list
+extern const base::Feature kLocalDatabaseManagerEnabled;
+extern const base::Feature kV4OnlyEnabled;
+extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
+
+base::ListValue GetFeatureStatusList();
+
+#endif  // COMPONENTS_SAFE_BROWSING_FEATURES_H_
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/renderer/BUILD.gn b/components/safe_browsing/renderer/BUILD.gn
index da1a4886..02239b4 100644
--- a/components/safe_browsing/renderer/BUILD.gn
+++ b/components/safe_browsing/renderer/BUILD.gn
@@ -12,6 +12,7 @@
     ]
     deps = [
       "//base",
+      "//components/safe_browsing:features",
       "//components/safe_browsing/common:common",
       "//content/public/renderer",
       "//ipc",
diff --git a/components/safe_browsing/renderer/DEPS b/components/safe_browsing/renderer/DEPS
index b7cc985c..15dc39e 100644
--- a/components/safe_browsing/renderer/DEPS
+++ b/components/safe_browsing/renderer/DEPS
@@ -1,7 +1,8 @@
 include_rules = [
   "+content/public/renderer",
+    "+components/safe_browsing",
   "+third_party/WebKit/public/platform",
   "+third_party/WebKit/public/web",
   "+ipc",
   "+mojo/public/cpp",
-]
\ No newline at end of file
+]
diff --git a/components/safe_browsing/renderer/threat_dom_details.cc b/components/safe_browsing/renderer/threat_dom_details.cc
index c3d712b..9fd9af5 100644
--- a/components/safe_browsing/renderer/threat_dom_details.cc
+++ b/components/safe_browsing/renderer/threat_dom_details.cc
@@ -16,6 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "components/safe_browsing/common/safebrowsing_types.h"
+#include "components/safe_browsing/features.h"
 #include "content/public/renderer/render_frame.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
@@ -35,15 +36,6 @@
 // messages generated by ThreatDOMDetails.
 using ElementToNodeMap = std::map<blink::WebNode, size_t>;
 
-// This Feature specifies which non-resource HTML Elements to collect based on
-// their tag and attributes. It's a single param containing a comma-separated
-// list of pairs. For example: "tag1,id,tag1,height,tag2,foo" - this will
-// collect elements with tag "tag1" that have attribute "id" or "height" set,
-// and elements of tag "tag2" if they have attribute "foo" set. All tag names
-// and attributes should be lower case.
-const base::Feature kThreatDomDetailsTagAndAttributeFeature{
-    "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // The name of the param containing the tags and attributes list.
 const char kTagAndAttributeParamName[] = "tag_attribute_csv";
 
diff --git a/components/safe_browsing/renderer/threat_dom_details.h b/components/safe_browsing/renderer/threat_dom_details.h
index 0f48d0b..76c32a3d 100644
--- a/components/safe_browsing/renderer/threat_dom_details.h
+++ b/components/safe_browsing/renderer/threat_dom_details.h
@@ -19,7 +19,6 @@
 
 namespace safe_browsing {
 
-extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
 extern const char kTagAndAttributeParamName[];
 
 // Represents the tag name of an HTML Element and its associated attributes.
diff --git a/components/safe_browsing/web_ui/BUILD.gn b/components/safe_browsing/web_ui/BUILD.gn
index 0c24b46..f1234f9 100644
--- a/components/safe_browsing/web_ui/BUILD.gn
+++ b/components/safe_browsing/web_ui/BUILD.gn
@@ -13,6 +13,7 @@
     "//base",
     "//components/resources:components_resources_grit",
     "//components/resources:components_scaled_resources_grit",
+    "//components/safe_browsing:features",
     "//components/strings:components_strings_grit",
     "//content/public/browser",
     "//net",
diff --git a/components/safe_browsing/web_ui/resources/safe_browsing.css b/components/safe_browsing/web_ui/resources/safe_browsing.css
index 0bacdd7f..93c0cfb 100644
--- a/components/safe_browsing/web_ui/resources/safe_browsing.css
+++ b/components/safe_browsing/web_ui/resources/safe_browsing.css
@@ -2,7 +2,28 @@
 /* Copyright 2017 The Chromium Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
-
+body {
+      color: rgb(48, 57, 66);
+      margin:15px;
+}
  p {
   white-space: pre-wrap;
 }
+
+.experiments {
+  background-color: #fbfbfb;
+    border: 1px solid #cecece;
+    border-radius: 3px;
+    padding: 19px;
+    line-height: 1.5;
+}
+
+#sbTitle {
+    font-size: 2em;
+    margin-bottom: 0.8em;
+}
+
+h1, h2, h3, p {
+    font-weight: normal;
+    line-height: 1;
+    }
diff --git a/components/safe_browsing/web_ui/resources/safe_browsing.html b/components/safe_browsing/web_ui/resources/safe_browsing.html
index 31ae761..2578e08 100644
--- a/components/safe_browsing/web_ui/resources/safe_browsing.html
+++ b/components/safe_browsing/web_ui/resources/safe_browsing.html
@@ -8,10 +8,17 @@
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/util.js"></script>
+  <script src="safe_browsing.js"></script>
 </head>
 <body>
-  <h1>Safe Browsing</h1>
+<div id="header">
+  <h1 id="sbTitle">Safe Browsing</h1>
+  </div>
   <p>$i18n{sbUnderConstruction}</p>
+    <h2>Experiments</h2>
+  <div class="experiments">
+  <p id="experimentsList"></p>
+  </div>
   <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
 </html>
diff --git a/components/safe_browsing/web_ui/resources/safe_browsing.js b/components/safe_browsing/web_ui/resources/safe_browsing.js
new file mode 100644
index 0000000..d47e9a2
--- /dev/null
+++ b/components/safe_browsing/web_ui/resources/safe_browsing.js
@@ -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. */
+
+   cr.define('safe_browsing', function() {
+     'use strict';
+
+    function initialize() {
+     chrome.send('expParamList',[]);
+    }
+
+   function addExperiment(result) {
+   var resLength = result.length;
+   var experimentsListFormatted="";
+
+for (var i = 0; i < resLength; i+=2) {
+    experimentsListFormatted += "<div>" + result[i+1] + " --- " + result [i] +
+    "</div>";}
+     $('experimentsList').innerHTML = experimentsListFormatted;
+  }
+
+    return {
+     addExperiment: addExperiment,
+      initialize: initialize,
+    };
+
+});
+
+document.addEventListener('DOMContentLoaded', safe_browsing.initialize);
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.cc b/components/safe_browsing/web_ui/safe_browsing_ui.cc
index 761b7cb..fe19f300 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -1,28 +1,41 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #include "components/safe_browsing/web_ui/safe_browsing_ui.h"
+
+#include <algorithm>
+#include <utility>
+#include "base/macros.h"
+#include "base/values.h"
 #include "components/grit/components_resources.h"
 #include "components/grit/components_scaled_resources.h"
+#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/web_ui/constants.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-
+#include "content/public/browser/web_ui_message_handler.h"
+namespace safe_browsing {
 SafeBrowsingUI::SafeBrowsingUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui) {
   // Set up the chrome://safe-browsing source.
+
   content::WebUIDataSource* html_source = content::WebUIDataSource::Create(
       safe_browsing::kChromeUISafeBrowsingHost);
 
+  // Register callback handler.
+  // Handles messages from JavaScript to C++ via chrome.send().
+  web_ui->AddMessageHandler(base::MakeUnique<SafeBrowsingUIHandler>());
+
   // Add localized string resources.
   html_source->AddLocalizedString("sbUnderConstruction",
                                   IDS_SB_UNDER_CONSTRUCTION);
 
   // Add required resources.
   html_source->AddResourcePath("safe_browsing.css", IDR_SAFE_BROWSING_CSS);
+  html_source->AddResourcePath("safe_browsing.js", IDR_SAFE_BROWSING_JS);
   html_source->SetDefaultResource(IDR_SAFE_BROWSING_HTML);
 
   content::BrowserContext* browser_context =
@@ -31,3 +44,19 @@
 }
 
 SafeBrowsingUI::~SafeBrowsingUI() {}
+
+SafeBrowsingUIHandler::SafeBrowsingUIHandler(){};
+
+void SafeBrowsingUIHandler::ExpParamList(const base::ListValue* unused) {
+  AllowJavascript();
+  CallJavascriptFunction("safe_browsing.addExperiment", GetFeatureStatusList());
+}
+
+void SafeBrowsingUIHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "expParamList",
+      base::Bind(&SafeBrowsingUIHandler::ExpParamList, base::Unretained(this)));
+}
+
+SafeBrowsingUIHandler::~SafeBrowsingUIHandler() {}
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.h b/components/safe_browsing/web_ui/safe_browsing_ui.h
index 440fae2..816c234 100644
--- a/components/safe_browsing/web_ui/safe_browsing_ui.h
+++ b/components/safe_browsing/web_ui/safe_browsing_ui.h
@@ -1,13 +1,32 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SAFE_BROWSING_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_SAFE_BROWSING_UI_H_
+#ifndef COMPONENTS_SAFE_BROWSING_WEBUI_SAFE_BROWSING_UI_H_
+#define COMPONENTS_SAFE_BROWSING_WEBUI_SAFE_BROWSING_UI_H_
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/macros.h"
+#include "base/values.h"
 #include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace safe_browsing {
+class SafeBrowsingUIHandler : public content::WebUIMessageHandler {
+ public:
+  SafeBrowsingUIHandler();
+  ~SafeBrowsingUIHandler() override;
+  void ExpParamList(const base::ListValue* args);
+  void RegisterMessages() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUIHandler);
+};
 
 // The WebUI for chrome://safe-browsing
 class SafeBrowsingUI : public content::WebUIController {
@@ -18,5 +37,6 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUI);
 };
+}  // namespace safe_browsing
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SAFE_BROWSING_UI_H_
+#endif  // COMPONENTS_SAFE_BROWSING_WEBUI_SAFE_BROWSING_UI_H_
diff --git a/components/safe_browsing_db/BUILD.gn b/components/safe_browsing_db/BUILD.gn
index 031ccc7..a0869605 100644
--- a/components/safe_browsing_db/BUILD.gn
+++ b/components/safe_browsing_db/BUILD.gn
@@ -217,6 +217,7 @@
   ]
   deps = [
     "//base",
+    "//components/safe_browsing:features",
   ]
 }
 
diff --git a/components/safe_browsing_db/DEPS b/components/safe_browsing_db/DEPS
index 55dc17a..341bbf0 100644
--- a/components/safe_browsing_db/DEPS
+++ b/components/safe_browsing_db/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/data_use_measurement/core",
   "+components/safe_browsing/common/safe_browsing_prefs.h",
+  "+components/safe_browsing/features.h",
   "+components/variations",
   "+components/version_info",
   "+content/public/browser",
diff --git a/components/safe_browsing_db/v4_feature_list.cc b/components/safe_browsing_db/v4_feature_list.cc
index 9d166e9..8185e6fc 100644
--- a/components/safe_browsing_db/v4_feature_list.cc
+++ b/components/safe_browsing_db/v4_feature_list.cc
@@ -2,22 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/feature_list.h"
 #include "components/safe_browsing_db/v4_feature_list.h"
 
+#include "base/feature_list.h"
+#include "components/safe_browsing/features.h"
+
 namespace safe_browsing {
 
 namespace V4FeatureList {
 
-namespace {
-
-const base::Feature kLocalDatabaseManagerEnabled{
-    "SafeBrowsingV4LocalDatabaseManagerEnabled",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kV4OnlyEnabled{"SafeBrowsingV4OnlyEnabled",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
-
 bool IsV4OnlyEnabled() {
   return base::FeatureList::IsEnabled(kV4OnlyEnabled);
 }
@@ -27,8 +20,6 @@
          IsV4OnlyEnabled();
 }
 
-}  // namespace
-
 V4UsageStatus GetV4UsageStatus() {
   V4UsageStatus v4_usage_status;
   if (safe_browsing::V4FeatureList::IsV4OnlyEnabled()) {
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 1b346e2..c93cb0a3 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -36,9 +36,10 @@
 const base::Feature kSyncClearDataOnPassphraseEncryption{
     "ClearSyncDataOnPassphraseEncryption", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Gates registration and construction of user events machinery.
+// Gates registration and construction of user events machinery. Enabled by
+// default as each use case should have their own gating feature as well.
 const base::Feature kSyncUserEvents{"SyncUserEvents",
-                                    base::FEATURE_DISABLED_BY_DEFAULT};
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Gates registration for user language detection events.
 const base::Feature kSyncUserLanguageDetectionEvents{
diff --git a/components/sync/engine_impl/commit.cc b/components/sync/engine_impl/commit.cc
index 7f17268..73a2e73c 100644
--- a/components/sync/engine_impl/commit.cc
+++ b/components/sync/engine_impl/commit.cc
@@ -50,15 +50,16 @@
   DCHECK(cleaned_up_);
 }
 
-Commit* Commit::Init(ModelTypeSet requested_types,
-                     ModelTypeSet enabled_types,
-                     size_t max_entries,
-                     const std::string& account_name,
-                     const std::string& cache_guid,
-                     bool cookie_jar_mismatch,
-                     bool cookie_jar_empty,
-                     CommitProcessor* commit_processor,
-                     ExtensionsActivity* extensions_activity) {
+// static
+std::unique_ptr<Commit> Commit::Init(ModelTypeSet requested_types,
+                                     ModelTypeSet enabled_types,
+                                     size_t max_entries,
+                                     const std::string& account_name,
+                                     const std::string& cache_guid,
+                                     bool cookie_jar_mismatch,
+                                     bool cookie_jar_empty,
+                                     CommitProcessor* commit_processor,
+                                     ExtensionsActivity* extensions_activity) {
   // Gather per-type contributions.
   ContributionMap contributions;
   commit_processor->GatherCommitContributions(requested_types, max_entries,
@@ -109,8 +110,8 @@
   }
 
   // If we made it this far, then we've successfully prepared a commit message.
-  return new Commit(std::move(contributions), message,
-                    extensions_activity_buffer);
+  return base::MakeUnique<Commit>(std::move(contributions), message,
+                                  extensions_activity_buffer);
 }
 
 SyncerError Commit::PostAndProcessResponse(
diff --git a/components/sync/engine_impl/commit.h b/components/sync/engine_impl/commit.h
index 5e19e2f..d022110 100644
--- a/components/sync/engine_impl/commit.h
+++ b/components/sync/engine_impl/commit.h
@@ -47,15 +47,15 @@
   ~Commit();
 
   // |extensions_activity| may be null.
-  static Commit* Init(ModelTypeSet requested_types,
-                      ModelTypeSet enabled_types,
-                      size_t max_entries,
-                      const std::string& account_name,
-                      const std::string& cache_guid,
-                      bool cookie_jar_mismatch,
-                      bool cookie_jar_empty,
-                      CommitProcessor* commit_processor,
-                      ExtensionsActivity* extensions_activity);
+  static std::unique_ptr<Commit> Init(ModelTypeSet requested_types,
+                                      ModelTypeSet enabled_types,
+                                      size_t max_entries,
+                                      const std::string& account_name,
+                                      const std::string& cache_guid,
+                                      bool cookie_jar_mismatch,
+                                      bool cookie_jar_empty,
+                                      CommitProcessor* commit_processor,
+                                      ExtensionsActivity* extensions_activity);
 
   // |extensions_activity| may be null.
   SyncerError PostAndProcessResponse(NudgeTracker* nudge_tracker,
diff --git a/components/sync/engine_impl/net/server_connection_manager.cc b/components/sync/engine_impl/net/server_connection_manager.cc
index 76e6246..5bc867b 100644
--- a/components/sync/engine_impl/net/server_connection_manager.cc
+++ b/components/sync/engine_impl/net/server_connection_manager.cc
@@ -222,7 +222,7 @@
   // Copy over the token to previous invalid token.
   if (!auth_token_.empty()) {
     previously_invalidated_token.assign(auth_token_);
-    auth_token_ = std::string();
+    auth_token_.clear();
   }
 }
 
diff --git a/components/sync/engine_impl/net/server_connection_manager.h b/components/sync/engine_impl/net/server_connection_manager.h
index 052b51e..d61451d 100644
--- a/components/sync/engine_impl/net/server_connection_manager.h
+++ b/components/sync/engine_impl/net/server_connection_manager.h
@@ -228,6 +228,27 @@
   // ServerConnectionManager to cleanup active connections.
   void OnConnectionDestroyed(Connection* connection);
 
+ private:
+  // A class to help deal with cleaning up active Connection objects when (for
+  // ex) multiple early-exits are present in some scope. ScopedConnectionHelper
+  // informs the ServerConnectionManager before the Connection object it takes
+  // ownership of is destroyed.
+  class ScopedConnectionHelper {
+   public:
+    // |manager| must outlive this. Takes ownership of |connection|.
+    ScopedConnectionHelper(ServerConnectionManager* manager,
+                           Connection* connection);
+    ~ScopedConnectionHelper();
+    Connection* get();
+
+   private:
+    ServerConnectionManager* manager_;
+    std::unique_ptr<Connection> connection_;
+    DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper);
+  };
+
+  void NotifyStatusChanged();
+
   // The sync_server_ is the server that requests will be made to.
   std::string sync_server_;
 
@@ -266,27 +287,6 @@
   // it if necessary.
   Connection* active_connection_;
 
- private:
-  // A class to help deal with cleaning up active Connection objects when (for
-  // ex) multiple early-exits are present in some scope. ScopedConnectionHelper
-  // informs the ServerConnectionManager before the Connection object it takes
-  // ownership of is destroyed.
-  class ScopedConnectionHelper {
-   public:
-    // |manager| must outlive this. Takes ownership of |connection|.
-    ScopedConnectionHelper(ServerConnectionManager* manager,
-                           Connection* connection);
-    ~ScopedConnectionHelper();
-    Connection* get();
-
-   private:
-    ServerConnectionManager* manager_;
-    std::unique_ptr<Connection> connection_;
-    DISALLOW_COPY_AND_ASSIGN(ScopedConnectionHelper);
-  };
-
-  void NotifyStatusChanged();
-
   CancelationSignal* const cancelation_signal_;
   bool signal_handler_registered_;
 
diff --git a/components/sync/engine_impl/net/url_translator.cc b/components/sync/engine_impl/net/url_translator.cc
index 478aa91a..8ec49163 100644
--- a/components/sync/engine_impl/net/url_translator.cc
+++ b/components/sync/engine_impl/net/url_translator.cc
@@ -22,15 +22,6 @@
 #endif  // defined(GOOGLE_CHROME_BUILD)
 }  // namespace
 
-// Convenience wrappers around CgiEscapePath().
-string CgiEscapeString(const char* src) {
-  return CgiEscapeString(string(src));
-}
-
-string CgiEscapeString(const string& src) {
-  return net::EscapeUrlEncodedData(src, true);
-}
-
 // This method appends the query string to the sync server path.
 string MakeSyncServerPath(const string& path, const string& query_string) {
   string result = path;
@@ -42,10 +33,10 @@
 string MakeSyncQueryString(const string& client_id) {
   string query;
   query += kParameterClient;
-  query += "=" + CgiEscapeString(kClientName);
+  query += "=" + net::EscapeUrlEncodedData(kClientName, true);
   query += "&";
   query += kParameterClientID;
-  query += "=" + CgiEscapeString(client_id);
+  query += "=" + net::EscapeUrlEncodedData(client_id, true);
   return query;
 }
 
diff --git a/components/sync/engine_impl/net/url_translator.h b/components/sync/engine_impl/net/url_translator.h
index bec8384..c5373ab 100644
--- a/components/sync/engine_impl/net/url_translator.h
+++ b/components/sync/engine_impl/net/url_translator.h
@@ -12,10 +12,6 @@
 // Contains the declaration of a few helper functions used for generating sync
 // URLs.
 
-// Convenience wrappers around CgiEscapePath(), used by gaia_auth.
-std::string CgiEscapeString(const char* src);
-std::string CgiEscapeString(const std::string& src);
-
 // This method appends the query string to the sync server path.
 std::string MakeSyncServerPath(const std::string& path,
                                const std::string& query_string);
diff --git a/components/sync/engine_impl/process_updates_util.cc b/components/sync/engine_impl/process_updates_util.cc
index fbbdd22..37c1e3b 100644
--- a/components/sync/engine_impl/process_updates_util.cc
+++ b/components/sync/engine_impl/process_updates_util.cc
@@ -281,25 +281,23 @@
                               const SyncEntityList& applicable_updates,
                               StatusController* status,
                               UpdateCounters* counters) {
-  for (SyncEntityList::const_iterator update_it = applicable_updates.begin();
-       update_it != applicable_updates.end(); ++update_it) {
-    DCHECK_EQ(type, GetModelType(**update_it));
-    if (!UpdateContainsNewVersion(trans, **update_it)) {
+  for (const auto* update : applicable_updates) {
+    DCHECK_EQ(type, GetModelType(*update));
+    if (!UpdateContainsNewVersion(trans, *update)) {
       status->increment_num_reflected_updates_downloaded_by(1);
       counters->num_reflected_updates_received++;
     }
-    if ((*update_it)->deleted()) {
+    if (update->deleted()) {
       status->increment_num_tombstone_updates_downloaded_by(1);
       counters->num_tombstone_updates_received++;
     }
-    VerifyResult verify_result = VerifyUpdate(trans, **update_it, type);
+    VerifyResult verify_result = VerifyUpdate(trans, *update, type);
     if (verify_result != VERIFY_SUCCESS && verify_result != VERIFY_UNDELETE)
       continue;
-    ProcessUpdate(**update_it, dir->GetCryptographer(trans), trans);
-    if ((*update_it)->ByteSize() > 0) {
+    ProcessUpdate(*update, dir->GetCryptographer(trans), trans);
+    if (update->ByteSize() > 0) {
       SyncRecordDatatypeBin("DataUse.Sync.Download.Bytes",
-                            ModelTypeToHistogramInt(type),
-                            (*update_it)->ByteSize());
+                            ModelTypeToHistogramInt(type), update->ByteSize());
     }
     UMA_HISTOGRAM_SPARSE_SLOWLY("DataUse.Sync.Download.Count",
                                 ModelTypeToHistogramInt(type));
diff --git a/components/sync/model/attachments/attachment_store.h b/components/sync/model/attachments/attachment_store.h
index f302b343..58a09215 100644
--- a/components/sync/model/attachments/attachment_store.h
+++ b/components/sync/model/attachments/attachment_store.h
@@ -198,7 +198,7 @@
                          Component sync_component);
 
   // |sync_component_| is passed to frontend when sync related operations are
-  // perfromed.
+  // performed.
   const Component sync_component_;
 
   DISALLOW_COPY_AND_ASSIGN(AttachmentStoreForSync);
diff --git a/components/sync/syncable/base_node.h b/components/sync/syncable/base_node.h
index ac53ace..fc3a765 100644
--- a/components/sync/syncable/base_node.h
+++ b/components/sync/syncable/base_node.h
@@ -39,7 +39,6 @@
 class BaseTransaction;
 
 namespace syncable {
-class BaseTransaction;
 class Entry;
 class Id;
 }
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc
index 19b8879..8cb219a 100644
--- a/components/sync/test/engine/mock_connection_manager.cc
+++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -763,15 +763,10 @@
 
 void MockConnectionManager::UpdateConnectionStatus() {
   if (!server_reachable_) {
-    server_status_ = HttpResponse::CONNECTION_UNAVAILABLE;
+    SetServerStatus(HttpResponse::CONNECTION_UNAVAILABLE);
   } else {
-    server_status_ = HttpResponse::SERVER_CONNECTION_OK;
+    SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
   }
 }
 
-void MockConnectionManager::SetServerStatus(
-    HttpResponse::ServerConnectionCode server_status) {
-  server_status_ = server_status;
-}
-
 }  // namespace syncer
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h
index fba4317c..617c9fa 100644
--- a/components/sync/test/engine/mock_connection_manager.h
+++ b/components/sync/test/engine/mock_connection_manager.h
@@ -255,7 +255,7 @@
   // requests.
   void UpdateConnectionStatus();
 
-  void SetServerStatus(HttpResponse::ServerConnectionCode server_status);
+  using ServerConnectionManager::SetServerStatus;
 
   // Return by copy to be thread-safe.
   const std::string store_birthday() {
@@ -272,7 +272,7 @@
   // Adds a new progress marker to the last update.
   sync_pb::DataTypeProgressMarker* AddUpdateProgressMarker();
 
-  void ResetAuthToken() { auth_token_.clear(); }
+  void ResetAuthToken() { InvalidateAndClearAuthToken(); }
 
  private:
   sync_pb::SyncEntity* AddUpdateFull(syncable::Id id,
diff --git a/components/update_client/background_downloader_win.cc b/components/update_client/background_downloader_win.cc
index d383e1a1..075d675a 100644
--- a/components/update_client/background_downloader_win.cc
+++ b/components/update_client/background_downloader_win.cc
@@ -675,8 +675,6 @@
   return false;
 }
 
-// Creates or opens a job for the given url and queues it up. Tries to
-// install a job observer but continues on if an observer can't be set up.
 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url,
                                            ComPtr<IBackgroundCopyJob>* job) {
   DCHECK(task_runner()->RunsTasksInCurrentSequence());
@@ -699,6 +697,9 @@
     return hr;
   }
 
+  const bool is_new_job = hr == S_OK;
+  UMA_HISTOGRAM_BOOLEAN("UpdateClient.BackgroundDownloaderNewJob", is_new_job);
+
   hr = local_job->Resume();
   if (FAILED(hr)) {
     CleanupJob(local_job);
@@ -717,7 +718,7 @@
                     bits_manager_, &jobs);
   if (SUCCEEDED(hr) && !jobs.empty()) {
     *job = jobs.front();
-    return hr;
+    return S_FALSE;
   }
 
   ComPtr<IBackgroundCopyJob> local_job;
diff --git a/components/update_client/background_downloader_win.h b/components/update_client/background_downloader_win.h
index be0f26cc..237aea6 100644
--- a/components/update_client/background_downloader_win.h
+++ b/components/update_client/background_downloader_win.h
@@ -87,6 +87,9 @@
   void StartTimer();
   void OnTimer();
 
+  // Creates or opens a job for the given url and queues it up. Returns S_OK if
+  // a new job was created or S_FALSE if an existing job for the |url| was found
+  // in the BITS queue.
   HRESULT QueueBitsJob(const GURL& url,
                        Microsoft::WRL::ComPtr<IBackgroundCopyJob>* job);
   HRESULT CreateOrOpenJob(const GURL& url,
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index f0586d0..d868afd 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -10,6 +10,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
@@ -26,52 +27,66 @@
 using FlatDomains = flatbuffers::Vector<FlatStringOffset>;
 using FlatDomainsOffset = flatbuffers::Offset<FlatDomains>;
 
+using ActivationTypeMap =
+    base::flat_map<proto::ActivationType, flat::ActivationType>;
+using ElementTypeMap = base::flat_map<proto::ElementType, flat::ElementType>;
+
 // Maps proto::ActivationType to flat::ActivationType.
-const base::flat_map<proto::ActivationType, flat::ActivationType>
-    kActivationTypeMap(
-        {
-            {proto::ACTIVATION_TYPE_UNSPECIFIED, flat::ActivationType_NONE},
-            {proto::ACTIVATION_TYPE_DOCUMENT, flat::ActivationType_DOCUMENT},
-            // ELEMHIDE is not supported.
-            {proto::ACTIVATION_TYPE_ELEMHIDE, flat::ActivationType_NONE},
-            // GENERICHIDE is not supported.
-            {proto::ACTIVATION_TYPE_GENERICHIDE, flat::ActivationType_NONE},
-            {proto::ACTIVATION_TYPE_GENERICBLOCK,
-             flat::ActivationType_GENERIC_BLOCK},
-        },
-        base::KEEP_FIRST_OF_DUPES);
+const ActivationTypeMap& GetActivationTypeMap() {
+  CR_DEFINE_STATIC_LOCAL(
+      ActivationTypeMap, activation_type_map,
+      (
+          {
+              {proto::ACTIVATION_TYPE_UNSPECIFIED, flat::ActivationType_NONE},
+              {proto::ACTIVATION_TYPE_DOCUMENT, flat::ActivationType_DOCUMENT},
+              // ELEMHIDE is not supported.
+              {proto::ACTIVATION_TYPE_ELEMHIDE, flat::ActivationType_NONE},
+              // GENERICHIDE is not supported.
+              {proto::ACTIVATION_TYPE_GENERICHIDE, flat::ActivationType_NONE},
+              {proto::ACTIVATION_TYPE_GENERICBLOCK,
+               flat::ActivationType_GENERIC_BLOCK},
+          },
+          base::KEEP_FIRST_OF_DUPES));
+  return activation_type_map;
+}
 
 // Maps proto::ElementType to flat::ElementType.
-const base::flat_map<proto::ElementType, flat::ElementType> kElementTypeMap(
-    {
-        {proto::ELEMENT_TYPE_UNSPECIFIED, flat::ElementType_NONE},
-        {proto::ELEMENT_TYPE_OTHER, flat::ElementType_OTHER},
-        {proto::ELEMENT_TYPE_SCRIPT, flat::ElementType_SCRIPT},
-        {proto::ELEMENT_TYPE_IMAGE, flat::ElementType_IMAGE},
-        {proto::ELEMENT_TYPE_STYLESHEET, flat::ElementType_STYLESHEET},
-        {proto::ELEMENT_TYPE_OBJECT, flat::ElementType_OBJECT},
-        {proto::ELEMENT_TYPE_XMLHTTPREQUEST, flat::ElementType_XMLHTTPREQUEST},
-        {proto::ELEMENT_TYPE_OBJECT_SUBREQUEST,
-         flat::ElementType_OBJECT_SUBREQUEST},
-        {proto::ELEMENT_TYPE_SUBDOCUMENT, flat::ElementType_SUBDOCUMENT},
-        {proto::ELEMENT_TYPE_PING, flat::ElementType_PING},
-        {proto::ELEMENT_TYPE_MEDIA, flat::ElementType_MEDIA},
-        {proto::ELEMENT_TYPE_FONT, flat::ElementType_FONT},
-        // Filtering popups is not supported.
-        {proto::ELEMENT_TYPE_POPUP, flat::ElementType_NONE},
-        {proto::ELEMENT_TYPE_WEBSOCKET, flat::ElementType_WEBSOCKET},
-    },
-    base::KEEP_FIRST_OF_DUPES);
+const ElementTypeMap& GetElementTypeMap() {
+  CR_DEFINE_STATIC_LOCAL(
+      ElementTypeMap, element_type_map,
+      (
+          {
+              {proto::ELEMENT_TYPE_UNSPECIFIED, flat::ElementType_NONE},
+              {proto::ELEMENT_TYPE_OTHER, flat::ElementType_OTHER},
+              {proto::ELEMENT_TYPE_SCRIPT, flat::ElementType_SCRIPT},
+              {proto::ELEMENT_TYPE_IMAGE, flat::ElementType_IMAGE},
+              {proto::ELEMENT_TYPE_STYLESHEET, flat::ElementType_STYLESHEET},
+              {proto::ELEMENT_TYPE_OBJECT, flat::ElementType_OBJECT},
+              {proto::ELEMENT_TYPE_XMLHTTPREQUEST,
+               flat::ElementType_XMLHTTPREQUEST},
+              {proto::ELEMENT_TYPE_OBJECT_SUBREQUEST,
+               flat::ElementType_OBJECT_SUBREQUEST},
+              {proto::ELEMENT_TYPE_SUBDOCUMENT, flat::ElementType_SUBDOCUMENT},
+              {proto::ELEMENT_TYPE_PING, flat::ElementType_PING},
+              {proto::ELEMENT_TYPE_MEDIA, flat::ElementType_MEDIA},
+              {proto::ELEMENT_TYPE_FONT, flat::ElementType_FONT},
+              // Filtering popups is not supported.
+              {proto::ELEMENT_TYPE_POPUP, flat::ElementType_NONE},
+              {proto::ELEMENT_TYPE_WEBSOCKET, flat::ElementType_WEBSOCKET},
+          },
+          base::KEEP_FIRST_OF_DUPES));
+  return element_type_map;
+}
 
 flat::ActivationType ProtoToFlatActivationType(proto::ActivationType type) {
-  const auto it = kActivationTypeMap.find(type);
-  DCHECK(it != kActivationTypeMap.end());
+  const auto it = GetActivationTypeMap().find(type);
+  DCHECK(it != GetActivationTypeMap().end());
   return it->second;
 }
 
 flat::ElementType ProtoToFlatElementType(proto::ElementType type) {
-  const auto it = kElementTypeMap.find(type);
-  DCHECK(it != kElementTypeMap.end());
+  const auto it = GetElementTypeMap().find(type);
+  DCHECK(it != GetElementTypeMap().end());
   return it->second;
 }
 
@@ -235,12 +250,13 @@
     static_assert(flat::ElementType_ANY <= std::numeric_limits<uint16_t>::max(),
                   "Element types can not be stored in uint16_t.");
 
-    // Ensure all proto::ElementType(s) are mapped in |kElementTypeMap|.
-    DCHECK_EQ(proto::ELEMENT_TYPE_ALL, GetKeysMask(kElementTypeMap));
+    const ElementTypeMap& element_type_map = GetElementTypeMap();
+    // Ensure all proto::ElementType(s) are mapped in |element_type_map|.
+    DCHECK_EQ(proto::ELEMENT_TYPE_ALL, GetKeysMask(element_type_map));
 
     element_types_ = flat::ElementType_NONE;
 
-    for (const auto& pair : kElementTypeMap)
+    for (const auto& pair : element_type_map)
       if (rule_.element_types() & pair.first)
         element_types_ |= pair.second;
 
@@ -259,12 +275,13 @@
         flat::ActivationType_ANY <= std::numeric_limits<uint8_t>::max(),
         "Activation types can not be stored in uint8_t.");
 
-    // Ensure all proto::ActivationType(s) are mapped in |kActivationTypeMap|.
-    DCHECK_EQ(proto::ACTIVATION_TYPE_ALL, GetKeysMask(kActivationTypeMap));
+    const ActivationTypeMap& activation_type_map = GetActivationTypeMap();
+    // Ensure all proto::ActivationType(s) are mapped in |activation_type_map|.
+    DCHECK_EQ(proto::ACTIVATION_TYPE_ALL, GetKeysMask(activation_type_map));
 
     activation_types_ = flat::ActivationType_NONE;
 
-    for (const auto& pair : kActivationTypeMap)
+    for (const auto& pair : activation_type_map)
       if (rule_.activation_types() & pair.first)
         activation_types_ |= pair.second;
 
diff --git a/components/viz/BUILD.gn b/components/viz/BUILD.gn
new file mode 100644
index 0000000..e02e4340
--- /dev/null
+++ b/components/viz/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("//testing/test.gni")
+
+test("viz_unittests") {
+  sources = [
+    "run_all_unittests.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/viz/host:unit_tests",
+    "//components/viz/service:unit_tests",
+    "//mojo/edk/system",
+    "//ui/gl:test_support",
+  ]
+
+  if (!is_android) {
+    deps += [ "//components/viz/common:unit_tests" ]
+  }
+}
diff --git a/components/viz/DEPS b/components/viz/DEPS
new file mode 100644
index 0000000..565ba60
--- /dev/null
+++ b/components/viz/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/edk/embedder",
+  "+ui/gl",
+]
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index f60c6674..802694b 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -13,9 +13,13 @@
     "gl_helper_scaling.cc",
     "gl_helper_scaling.h",
     "quads/resource_format.h",
+    "resources/buffer_to_texture_target_map.cc",
+    "resources/buffer_to_texture_target_map.h",
     "resources/platform_color.h",
     "resources/resource_format_utils.cc",
     "resources/resource_format_utils.h",
+    "resources/resource_settings.cc",
+    "resources/resource_settings.h",
   ]
 
   deps = [
@@ -31,20 +35,17 @@
   ]
 }
 
+# These tests don't pass on Android so this target isn't in viz_unittests. If
+# you add a test here that should run on Android you need to change that.
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "gl_helper_unittest.cc",
+    "resources/buffer_to_texture_target_map_unittest.cc",
     "resources/platform_color_unittest.cc",
     "yuv_readback_unittest.cc",
   ]
 
-  if (!is_android) {
-    sources += [
-      # Many of these fail on Android with the test GL implementation.
-      "gl_helper_unittest.cc",
-    ]
-  }
-
   deps = [
     ":common",
     "//base/test:test_support",
diff --git a/cc/output/buffer_to_texture_target_map.cc b/components/viz/common/resources/buffer_to_texture_target_map.cc
similarity index 95%
rename from cc/output/buffer_to_texture_target_map.cc
rename to components/viz/common/resources/buffer_to_texture_target_map.cc
index f2343bd..83877f4 100644
--- a/cc/output/buffer_to_texture_target_map.cc
+++ b/components/viz/common/resources/buffer_to_texture_target_map.cc
@@ -1,7 +1,7 @@
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 
 #include <vector>
 
@@ -9,7 +9,7 @@
 #include "base/strings/string_split.h"
 #include "gpu/GLES2/gl2extchromium.h"
 
-namespace cc {
+namespace viz {
 
 BufferToTextureTargetMap StringToBufferToTextureTargetMap(
     const std::string& str) {
@@ -69,4 +69,4 @@
   return image_targets;
 }
 
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/output/buffer_to_texture_target_map.h b/components/viz/common/resources/buffer_to_texture_target_map.h
similarity index 67%
rename from cc/output/buffer_to_texture_target_map.h
rename to components/viz/common/resources/buffer_to_texture_target_map.h
index 95193fe7..b8b7364 100644
--- a/cc/output/buffer_to_texture_target_map.h
+++ b/components/viz/common/resources/buffer_to_texture_target_map.h
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_OUTPUT_BUFFER_TO_TEXTURE_TARGET_MAP_H_
-#define CC_OUTPUT_BUFFER_TO_TEXTURE_TARGET_MAP_H_
+#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_BUFFER_TO_TEXTURE_TARGET_MAP_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_BUFFER_TO_TEXTURE_TARGET_MAP_H_
 
 #include <map>
 #include <string>
 
-#include "cc/cc_export.h"
 #include "ui/gfx/buffer_types.h"
 
-namespace cc {
+namespace viz {
 // A map of GPU Memory Buffer usage/format to GL texture target.
 using BufferToTextureTargetKey = std::pair<gfx::BufferUsage, gfx::BufferFormat>;
 using BufferToTextureTargetMap = std::map<BufferToTextureTargetKey, uint32_t>;
@@ -19,18 +18,18 @@
 // Converts a serialized ImageTextureTargetsMap back to the runtime format.
 // Serialization takes the form:
 //   "usage,format,target;usage,format,target;...;usage,format,target"
-CC_EXPORT BufferToTextureTargetMap
-StringToBufferToTextureTargetMap(const std::string& str);
+BufferToTextureTargetMap StringToBufferToTextureTargetMap(
+    const std::string& str);
 
 // Converts an ImageTextureTargetsMap to a string representation of the format:
 //   "usage,format,target;usage,format,target;...;usage,format,target"
-CC_EXPORT std::string BufferToTextureTargetMapToString(
+std::string BufferToTextureTargetMapToString(
     const BufferToTextureTargetMap& map);
 
 // Returns a default-initialized BufferToTextureTargetsMap where every entry
 // maps to GL_TEXTURE_2D.
-CC_EXPORT BufferToTextureTargetMap DefaultBufferToTextureTargetMapForTesting();
+BufferToTextureTargetMap DefaultBufferToTextureTargetMapForTesting();
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_OUTPUT_BUFFER_TO_TEXTURE_TARGET_MAP_H_
+#endif  // COMPONENTS_VIZ_COMMON_RESOURCES_BUFFER_TO_TEXTURE_TARGET_MAP_H_
diff --git a/cc/output/buffer_to_texture_target_map_unittest.cc b/components/viz/common/resources/buffer_to_texture_target_map_unittest.cc
similarity index 91%
rename from cc/output/buffer_to_texture_target_map_unittest.cc
rename to components/viz/common/resources/buffer_to_texture_target_map_unittest.cc
index 79e6240..f037b998 100644
--- a/cc/output/buffer_to_texture_target_map_unittest.cc
+++ b/components/viz/common/resources/buffer_to_texture_target_map_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_types.h"
 
-namespace cc {
+namespace viz {
 namespace {
 
 // Ensures that a map populated with various values can be serialized to/from
@@ -34,4 +34,4 @@
 }
 
 }  // namespace
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/resources/resource_settings.cc b/components/viz/common/resources/resource_settings.cc
similarity index 81%
rename from cc/resources/resource_settings.cc
rename to components/viz/common/resources/resource_settings.cc
index 95600dc..2519c0c 100644
--- a/cc/resources/resource_settings.cc
+++ b/components/viz/common/resources/resource_settings.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/resources/resource_settings.h"
+#include "components/viz/common/resources/resource_settings.h"
 
-namespace cc {
+namespace viz {
 
 ResourceSettings::ResourceSettings() = default;
 
@@ -15,4 +15,4 @@
 ResourceSettings& ResourceSettings::operator=(const ResourceSettings& other) =
     default;
 
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/resources/resource_settings.h b/components/viz/common/resources/resource_settings.h
similarity index 64%
rename from cc/resources/resource_settings.h
rename to components/viz/common/resources/resource_settings.h
index d54ea29..e20fe8f 100644
--- a/cc/resources/resource_settings.h
+++ b/components/viz/common/resources/resource_settings.h
@@ -2,17 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_RESOURCES_RESOURCE_SETTINGS_H_
-#define CC_RESOURCES_RESOURCE_SETTINGS_H_
+#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_SETTINGS_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_SETTINGS_H_
 
-#include "cc/cc_export.h"
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 
-namespace cc {
+namespace viz {
 
 // ResourceSettings contains all the settings that are needed to create a
 // ResourceProvider.
-class CC_EXPORT ResourceSettings {
+class ResourceSettings {
  public:
   ResourceSettings();
   ResourceSettings(const ResourceSettings& other);
@@ -24,6 +23,6 @@
   BufferToTextureTargetMap buffer_to_texture_target_map;
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_RESOURCES_RESOURCE_SETTINGS_H_
+#endif  // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_SETTINGS_H_
diff --git a/components/viz/host/server_gpu_memory_buffer_manager.cc b/components/viz/host/server_gpu_memory_buffer_manager.cc
index ac36c93..afbc5e14 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager.cc
@@ -171,9 +171,9 @@
   if (iter == allocated_buffers_[client_id].end())
     return;
   DCHECK_NE(gfx::EMPTY_BUFFER, iter->second.type);
-  allocated_buffers_[client_id].erase(id);
   if (iter->second.type != gfx::SHARED_MEMORY_BUFFER)
     gpu_service_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
+  allocated_buffers_[client_id].erase(id);
 }
 
 void ServerGpuMemoryBufferManager::DestroyAllGpuMemoryBufferForClient(
diff --git a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
index 5d5e60b2..97ad09a 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/viz/host/server_gpu_memory_buffer_manager.h"
 
 #include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
 #include "services/ui/gpu/interfaces/gpu_service.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -225,7 +226,7 @@
   } configs[] = {
       {gfx::BufferUsage::SCANOUT, gfx::BufferFormat::YVU_420, {10, 20}, true},
       {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::ATC, {10, 20}, true},
-      {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {10, 20}, false},
+      {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {64, 64}, false},
   };
   for (const auto& config : configs) {
     gfx::GpuMemoryBufferHandle allocated_handle;
@@ -255,4 +256,28 @@
   }
 }
 
+TEST_F(ServerGpuMemoryBufferManagerTest, GpuMemoryBufferDestroyed) {
+  gfx::ClientNativePixmapFactory::ResetInstance();
+  TestGpuService gpu_service;
+  ServerGpuMemoryBufferManager manager(&gpu_service, 1);
+  base::Thread diff_thread("TestThread");
+  ASSERT_TRUE(diff_thread.Start());
+  std::unique_ptr<gfx::GpuMemoryBuffer> buffer;
+  base::RunLoop run_loop;
+  ASSERT_TRUE(diff_thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(
+                     [](ServerGpuMemoryBufferManager* manager,
+                        std::unique_ptr<gfx::GpuMemoryBuffer>* out_buffer,
+                        const base::Closure& callback) {
+                       *out_buffer = manager->CreateGpuMemoryBuffer(
+                           gfx::Size(64, 64), gfx::BufferFormat::YVU_420,
+                           gfx::BufferUsage::GPU_READ, gpu::kNullSurfaceHandle);
+                       callback.Run();
+                     },
+                     &manager, &buffer, run_loop.QuitClosure())));
+  run_loop.Run();
+  EXPECT_TRUE(buffer);
+  buffer.reset();
+}
+
 }  // namespace viz
diff --git a/components/viz/run_all_unittests.cc b/components/viz/run_all_unittests.cc
new file mode 100644
index 0000000..03910b9
--- /dev/null
+++ b/components/viz/run_all_unittests.cc
@@ -0,0 +1,38 @@
+// 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/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "ui/gl/test/gl_surface_test_support.h"
+
+namespace {
+
+class VizTestSuite : public base::TestSuite {
+ public:
+  VizTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {}
+  ~VizTestSuite() override = default;
+
+  // base::TestSuite:
+  void Initialize() override {
+    base::TestSuite::Initialize();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VizTestSuite);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  VizTestSuite test_suite(argc, argv);
+
+  mojo::edk::Init();
+
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&VizTestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 99d26e5..a6736aa 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -900,55 +900,6 @@
   return ui::IsRoleClickable(GetRole());
 }
 
-bool BrowserAccessibility::IsControl() const {
-  switch (GetRole()) {
-    case ui::AX_ROLE_BUTTON:
-    case ui::AX_ROLE_CHECK_BOX:
-    case ui::AX_ROLE_COLOR_WELL:
-    case ui::AX_ROLE_COMBO_BOX:
-    case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
-    case ui::AX_ROLE_LIST_BOX:
-    case ui::AX_ROLE_MENU:
-    case ui::AX_ROLE_MENU_BAR:
-    case ui::AX_ROLE_MENU_BUTTON:
-    case ui::AX_ROLE_MENU_ITEM:
-    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
-    case ui::AX_ROLE_MENU_ITEM_RADIO:
-    case ui::AX_ROLE_MENU_LIST_OPTION:
-    case ui::AX_ROLE_MENU_LIST_POPUP:
-    case ui::AX_ROLE_POP_UP_BUTTON:
-    case ui::AX_ROLE_RADIO_BUTTON:
-    case ui::AX_ROLE_SCROLL_BAR:
-    case ui::AX_ROLE_SEARCH_BOX:
-    case ui::AX_ROLE_SLIDER:
-    case ui::AX_ROLE_SPIN_BUTTON:
-    case ui::AX_ROLE_SWITCH:
-    case ui::AX_ROLE_TAB:
-    case ui::AX_ROLE_TEXT_FIELD:
-    case ui::AX_ROLE_TOGGLE_BUTTON:
-    case ui::AX_ROLE_TREE:
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool BrowserAccessibility::IsMenuRelated() const {
-  switch (GetRole()) {
-    case ui::AX_ROLE_MENU:
-    case ui::AX_ROLE_MENU_BAR:
-    case ui::AX_ROLE_MENU_BUTTON:
-    case ui::AX_ROLE_MENU_ITEM:
-    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
-    case ui::AX_ROLE_MENU_ITEM_RADIO:
-    case ui::AX_ROLE_MENU_LIST_OPTION:
-    case ui::AX_ROLE_MENU_LIST_POPUP:
-      return true;
-    default:
-      return false;
-  }
-}
-
 bool BrowserAccessibility::IsNativeTextControl() const {
   const std::string& html_tag = GetStringAttribute(ui::AX_ATTR_HTML_TAG);
   if (html_tag == "input") {
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 6716a2e..94630d7 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -355,8 +355,6 @@
   bool IsWebAreaForPresentationalIframe() const;
 
   virtual bool IsClickable() const;
-  bool IsControl() const;
-  bool IsMenuRelated() const;
   bool IsNativeTextControl() const;
   bool IsSimpleTextControl() const;
   // Indicates if this object is at the root of a rich edit text control.
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 4e9d9362..069cc63 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -292,7 +292,7 @@
     return true;
 
   // If it's not focusable but has a control role, then it's interesting.
-  if (IsControl())
+  if (ui::IsControl(GetRole()))
     return true;
 
   // Otherwise, the interesting nodes are leaf nodes with non-whitespace text.
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 0bfff2e..e256753 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -882,8 +882,7 @@
   // from its descendants.
   base::string16 value = browserAccessibility_->GetValue();
   if (browserAccessibility_->HasState(ui::AX_STATE_FOCUSABLE) &&
-      !browserAccessibility_->IsControl() &&
-      value.empty() &&
+      !IsControl(browserAccessibility_->GetRole()) && value.empty() &&
       [self internalRole] != ui::AX_ROLE_DATE_TIME &&
       [self internalRole] != ui::AX_ROLE_WEB_AREA &&
       [self internalRole] != ui::AX_ROLE_ROOT_WEB_AREA) {
@@ -1303,7 +1302,7 @@
 // internal
 - (BOOL)shouldExposeTitleUIElement {
   // VoiceOver ignores TitleUIElement if the element isn't a control.
-  if (!browserAccessibility_->IsControl())
+  if (!IsControl(browserAccessibility_->GetRole()))
     return false;
 
   ui::AXNameFrom nameFrom = static_cast<ui::AXNameFrom>(
@@ -2506,7 +2505,7 @@
   if (browserAccessibility_->IsClickable())
     [actions insertObject:NSAccessibilityPressAction atIndex:0];
 
-  if (browserAccessibility_->IsMenuRelated())
+  if (IsMenuRelated(browserAccessibility_->GetRole()))
     [actions addObject:NSAccessibilityCancelAction];
 
   if ([self internalRole] == ui::AX_ROLE_SLIDER) {
diff --git a/content/browser/accessibility/one_shot_accessibility_tree_search.cc b/content/browser/accessibility/one_shot_accessibility_tree_search.cc
index 45f1512..ff9c44d5 100644
--- a/content/browser/accessibility/one_shot_accessibility_tree_search.cc
+++ b/content/browser/accessibility/one_shot_accessibility_tree_search.cc
@@ -253,7 +253,7 @@
 
 bool AccessibilityControlPredicate(
     BrowserAccessibility* start, BrowserAccessibility* node) {
-  if (node->IsControl())
+  if (ui::IsControl(node->GetRole()))
     return true;
   if (node->HasState(ui::AX_STATE_FOCUSABLE) &&
       node->GetRole() != ui::AX_ROLE_IFRAME &&
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 3849406..23cadc69 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -48,7 +48,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/menu_item.h"
 #include "content/public/common/user_agent.h"
-#include "device/geolocation/geolocation_service_context.h"
 #include "jni/ContentViewCore_jni.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/android/view_android.h"
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 19b47d9..a3272d542 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -812,7 +812,7 @@
     data->display->SetOutputIsSecure(secure);
 }
 
-const cc::ResourceSettings& GpuProcessTransportFactory::GetResourceSettings()
+const viz::ResourceSettings& GpuProcessTransportFactory::GetResourceSettings()
     const {
   return renderer_settings_.resource_settings;
 }
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index 7c17eb8d..29f69eeb 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -53,7 +53,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::ResourceSettings& GetResourceSettings() const override;
+  const viz::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override;
   void RemoveObserver(ui::ContextFactoryObserver* observer) override;
 
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index 8bb8ef29..10f49de 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -13,13 +13,13 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/url_constants.h"
-#include "device/geolocation/geolocation_service_context.h"
+#include "device/geolocation/geolocation_context.h"
 #include "device/geolocation/geoposition.h"
 
 namespace content {
 namespace protocol {
 
-using GeolocationServiceContext = device::GeolocationServiceContext;
+using GeolocationContext = device::GeolocationContext;
 using Geoposition = device::Geoposition;
 
 namespace {
@@ -90,8 +90,8 @@
   if (!GetWebContents())
     return Response::InternalError();
 
-  GeolocationServiceContext* geolocation_context =
-      GetWebContents()->GetGeolocationServiceContext();
+  GeolocationContext* geolocation_context =
+      GetWebContents()->GetGeolocationContext();
   std::unique_ptr<Geoposition> geoposition(new Geoposition());
   if (latitude.isJust() && longitude.isJust() && accuracy.isJust()) {
     geoposition->latitude = latitude.fromJust();
@@ -111,8 +111,8 @@
   if (!GetWebContents())
     return Response::InternalError();
 
-  GeolocationServiceContext* geolocation_context =
-      GetWebContents()->GetGeolocationServiceContext();
+  GeolocationContext* geolocation_context =
+      GetWebContents()->GetGeolocationContext();
   geolocation_context->ClearOverride();
   return Response::OK();
 }
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index f15af73..6f7126c 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -1000,6 +1000,11 @@
 
   NotifyNavigationEntryCommitted(details);
 
+  if (active_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    UMA_HISTOGRAM_BOOLEAN("Navigation.SecureSchemeHasSSLStatus",
+                          !!active_entry->GetSSL().certificate);
+  }
+
   if (overriding_user_agent_changed)
     delegate_->UpdateOverridingUserAgent();
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index db6deec..292bb22 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -5829,8 +5829,7 @@
 
   // Submit the form.
   TestNavigationObserver observer(shell()->web_contents(), 1);
-  EXPECT_TRUE(ExecuteScript(
-      shell(), "window.domAutomationController.send(submitForm('isubmit'))"));
+  ExecuteScriptAsync(shell(), "submitForm('isubmit')");
   observer.Wait();
 
   EXPECT_EQ(2, controller.GetEntryCount());
@@ -6870,4 +6869,118 @@
             controller.GetLastCommittedEntry()->GetURL().spec());
 }
 
+// If the main frame does a load, it should not be reported as a subframe
+// navigation. This used to occur in the following case:
+// 1. You're on a site with frames.
+// 2. You do a subframe navigation. This was stored with transition type
+//    MANUAL_SUBFRAME.
+// 3. You navigate to some non-frame site.
+// 4. You navigate back to the page from step 2. Since it was initially
+//    MANUAL_SUBFRAME, it will be that same transition type here.
+// We don't want that, because any navigation that changes the toplevel frame
+// should be tracked as a toplevel navigation (this allows us to update the URL
+// bar, etc).
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       GoBackToManualSubFrame) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/navigation_controller/page_with_iframe.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  ASSERT_EQ(1U, root->child_count());
+  ASSERT_NE(nullptr, root->child_at(0));
+
+  {
+    // Iframe initial load.
+    LoadCommittedCapturer capturer(root->child_at(0));
+    GURL frame_url(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_1.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
+  }
+
+  {
+    // Iframe manual navigation.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    GURL frame_url(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_2.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
+  }
+
+  {
+    // Main frame navigation.
+    FrameNavigateParamsCapturer capturer(root);
+    GURL main_url_2(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_2.html"));
+    NavigateFrameToURL(root, main_url_2);
+    capturer.Wait();
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(), ui::PAGE_TRANSITION_LINK));
+  }
+
+  {
+    // Check the history before going back.
+    NavigationControllerImpl& controller =
+        static_cast<NavigationControllerImpl&>(
+            shell()->web_contents()->GetController());
+    EXPECT_EQ(3, controller.GetEntryCount());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(0)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    // TODO(creis, arthursonzogni): The correct PageTransition is still an open
+    // question. Maybe PAGE_TRANSITION_MANUAL_SUBFRAME is more appropriate.
+    // Please see https://crbug.com/740461.
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(1)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(2)->GetTransitionType(),
+        ui::PAGE_TRANSITION_LINK));
+  }
+
+  {
+    // Back.
+    FrameNavigateParamsCapturer capturer(root);
+    shell()->web_contents()->GetController().GoBack();
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FORWARD_BACK |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+  }
+
+  {
+    // Check the history again.
+    NavigationControllerImpl& controller =
+        static_cast<NavigationControllerImpl&>(
+            shell()->web_contents()->GetController());
+    EXPECT_EQ(3, controller.GetEntryCount());
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(0)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(1)->GetTransitionType(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                  ui::PAGE_TRANSITION_FORWARD_BACK |
+                                  ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        controller.GetEntryAtIndex(2)->GetTransitionType(),
+        ui::PAGE_TRANSITION_LINK));
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_delegate.cc b/content/browser/frame_host/render_frame_host_delegate.cc
index 6993977..cbe7d47 100644
--- a/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/content/browser/frame_host/render_frame_host_delegate.cc
@@ -72,8 +72,7 @@
   return NULL;
 }
 
-device::GeolocationServiceContext*
-RenderFrameHostDelegate::GetGeolocationServiceContext() {
+device::GeolocationContext* RenderFrameHostDelegate::GetGeolocationContext() {
   return nullptr;
 }
 
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index 3434b75..1009ba16 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -39,7 +39,7 @@
 }
 
 namespace device {
-class GeolocationServiceContext;
+class GeolocationContext;
 }
 
 namespace gfx {
@@ -189,8 +189,8 @@
       RenderFrameHost* render_frame_host,
       int browser_plugin_instance_id);
 
-  // Gets the GeolocationServiceContext associated with this delegate.
-  virtual device::GeolocationServiceContext* GetGeolocationServiceContext();
+  // Gets the GeolocationContext associated with this delegate.
+  virtual device::GeolocationContext* GetGeolocationContext();
 
   // Gets the WakeLock that serves wake lock requests from the renderer.
   virtual device::mojom::WakeLock* GetRendererWakeLock();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index d737a0b..fd98c05 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -106,7 +106,7 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
-#include "device/geolocation/geolocation_service_context.h"
+#include "device/geolocation/geolocation_context.h"
 #include "device/vr/features/features.h"
 #include "media/base/media_switches.h"
 #include "media/media_features.h"
@@ -2809,8 +2809,8 @@
 }
 
 void RenderFrameHostImpl::RegisterMojoInterfaces() {
-  device::GeolocationServiceContext* geolocation_service_context =
-      delegate_ ? delegate_->GetGeolocationServiceContext() : NULL;
+  device::GeolocationContext* geolocation_context =
+      delegate_ ? delegate_->GetGeolocationContext() : NULL;
 
 #if !defined(OS_ANDROID)
   // The default (no-op) implementation of InstalledAppProvider. On Android, the
@@ -2819,19 +2819,19 @@
       base::Bind(&InstalledAppProviderImplDefault::Create));
 #endif  // !defined(OS_ANDROID)
 
-  if (geolocation_service_context) {
-    // TODO(creis): Bind process ID here so that GeolocationServiceImpl
+  if (geolocation_context) {
+    // TODO(creis): Bind process ID here so that GeolocationImpl
     // can perform permissions checks once site isolation is complete.
     // crbug.com/426384
     // NOTE: At shutdown, there is no guaranteed ordering between destruction of
-    // this object and destruction of any GeolocationServicesImpls created via
+    // this object and destruction of any GeolocationsImpls created via
     // the below service registry, the reason being that the destruction of the
     // latter is triggered by receiving a message that the pipe was closed from
     // the renderer side. Hence, supply the reference to this object as a weak
     // pointer.
     GetInterfaceRegistry()->AddInterface(
-        base::Bind(&device::GeolocationServiceContext::CreateService,
-                   base::Unretained(geolocation_service_context)));
+        base::Bind(&device::GeolocationContext::Bind,
+                   base::Unretained(geolocation_context)));
   }
 
   GetInterfaceRegistry()->AddInterface<device::mojom::WakeLock>(base::Bind(
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 25940df..f66dac33 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1039,30 +1039,10 @@
 }
 
 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
-  // The logic below is weaker than "are all sites isolated" -- it asks instead,
-  // "is any site isolated". That's appropriate here since we're just trying to
-  // figure out if we're in any kind of site isolated mode, and in which case,
-  // we ignore the kSingleProcess and kProcessPerTab settings.
-  //
-  // TODO(nick): Move all handling of kSingleProcess/kProcessPerTab into
-  // SiteIsolationPolicy so we have a consistent behavior around the interaction
-  // of the process model flags.
-  //
-  // TODO(creis, alexmos): This looks like it will break single-process and
-  // process-per-tab.  See https://crbug.com/688617.
-  if (SiteIsolationPolicy::AreCrossProcessFramesPossible())
-    return true;
-
-  // False in the single-process mode, as it makes RVHs to accumulate
-  // in swapped_out_hosts_.
-  // True if we are using process-per-site-instance (default) or
-  // process-per-site (kProcessPerSite).
-  // TODO(nick): Move handling of kSingleProcess and kProcessPerTab into
-  // SiteIsolationPolicy.
+  // False in single-process mode, which does not support cross-process
+  // navigations or OOPIFs.
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kSingleProcess) &&
-         !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kProcessPerTab);
+      switches::kSingleProcess);
 }
 
 bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index df0c3ed..8dc24708 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -560,8 +560,8 @@
   void DeleteRenderFrameProxyHost(SiteInstance* site_instance);
 
   // Returns whether this tab should transition to a new renderer for
-  // cross-site URLs.  Enabled unless we see the --process-per-tab command line
-  // switch.  Can be overridden in unit tests.
+  // cross-site URLs.  Enabled unless we see the --single-process command line
+  // switch.
   bool ShouldTransitionCrossSite();
 
   // Returns true if for the navigation from |current_effective_url| to
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index a51635a..fde31285 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -402,8 +402,8 @@
   return GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds();
 }
 
-cc::BufferToTextureTargetMap CreateBufferToTextureTargetMap() {
-  cc::BufferToTextureTargetMap image_targets;
+viz::BufferToTextureTargetMap CreateBufferToTextureTargetMap() {
+  viz::BufferToTextureTargetMap image_targets;
   for (int usage_idx = 0; usage_idx <= static_cast<int>(gfx::BufferUsage::LAST);
        ++usage_idx) {
     gfx::BufferUsage usage = static_cast<gfx::BufferUsage>(usage_idx);
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
index 123dee0..5e4808f 100644
--- a/content/browser/gpu/compositor_util.h
+++ b/content/browser/gpu/compositor_util.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/values.h"
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -50,7 +50,7 @@
 CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkarounds();
 
 // Populate BufferToTextureTargetMap for all buffer usage/formats.
-CONTENT_EXPORT cc::BufferToTextureTargetMap CreateBufferToTextureTargetMap();
+CONTENT_EXPORT viz::BufferToTextureTargetMap CreateBufferToTextureTargetMap();
 
 }  // namespace content
 
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index c6ed491..4411641 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -125,7 +125,7 @@
 
 void PresentationServiceImpl::ListenForScreenAvailability(const GURL& url) {
   DVLOG(2) << "ListenForScreenAvailability " << url.spec();
-  if (!controller_delegate_) {
+  if (!controller_delegate_ || !url.is_valid()) {
     client_->OnScreenAvailabilityUpdated(
         url, blink::mojom::ScreenAvailability::UNAVAILABLE);
     return;
@@ -464,13 +464,13 @@
     ScreenAvailabilityListenerImpl(const GURL& availability_url,
                                    PresentationServiceImpl* service)
     : availability_url_(availability_url), service_(service) {
+  DCHECK(availability_url_.is_valid());
   DCHECK(service_);
   DCHECK(service_->client_.get());
 }
 
 PresentationServiceImpl::ScreenAvailabilityListenerImpl::
-~ScreenAvailabilityListenerImpl() {
-}
+    ~ScreenAvailabilityListenerImpl() = default;
 
 GURL PresentationServiceImpl::ScreenAvailabilityListenerImpl::
     GetAvailabilityUrl() const {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index caea5b7..54bb6e07 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -53,9 +53,9 @@
 #include "base/tracked_objects.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "components/metrics/single_sample_metrics.h"
 #include "components/tracing/common/tracing_switches.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/browser/appcache/appcache_dispatcher_host.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/background_fetch/background_fetch_service_impl.h"
@@ -2165,7 +2165,7 @@
 
   command_line->AppendSwitchASCII(
       switches::kContentImageTextureTarget,
-      cc::BufferToTextureTargetMapToString(CreateBufferToTextureTargetMap()));
+      viz::BufferToTextureTargetMapToString(CreateBufferToTextureTargetMap()));
 
   // Appending disable-gpu-feature switches due to software rendering list.
   GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 1b14ec9..6ff30ba 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -551,13 +551,6 @@
   prefs.background_video_track_optimization_enabled =
       base::FeatureList::IsEnabled(media::kBackgroundVideoTrackOptimization);
 
-  // TODO(servolk, asvitkine): Query the value directly when it is available in
-  // the renderer process. See https://crbug.com/681160.
-  prefs.enable_instant_source_buffer_gc =
-      variations::GetVariationParamByFeatureAsBool(
-          media::kMemoryPressureBasedSourceBufferGC,
-          "enable_instant_source_buffer_gc", false);
-
   GetContentClient()->browser()->OverrideWebkitPrefs(this, &prefs);
   return prefs;
 }
diff --git a/content/browser/resources/media/client_renderer.js b/content/browser/resources/media/client_renderer.js
index 3bdf538..5e85499 100644
--- a/content/browser/resources/media/client_renderer.js
+++ b/content/browser/resources/media/client_renderer.js
@@ -5,11 +5,15 @@
 var ClientRenderer = (function() {
   var ClientRenderer = function() {
     this.playerListElement = document.getElementById('player-list');
-    this.audioPropertiesTable =
-        document.getElementById('audio-property-table').querySelector('tbody');
-    this.playerPropertiesTable =
-        document.getElementById('player-property-table').querySelector('tbody');
-    this.logTable = document.getElementById('log').querySelector('tbody');
+    var audioTableElement = document.getElementById('audio-property-table');
+    if (audioTableElement)
+      this.audioPropertiesTable = audioTableElement.querySelector('tbody');
+    var playerTableElement = document.getElementById('player-property-table');
+    if (playerTableElement)
+      this.playerPropertiesTable = playerTableElement.querySelector('tbody');
+    var logElement = document.getElementById('log');
+    if (logElement)
+      this.logTable = logElement.querySelector('tbody');
     this.graphElement = document.getElementById('graphs');
     this.audioPropertyName = document.getElementById('audio-property-name');
 
@@ -23,18 +27,23 @@
 
     this.filterFunction = function() { return true; };
     this.filterText = document.getElementById('filter-text');
-    this.filterText.onkeyup = this.onTextChange_.bind(this);
+    if (this.filterText)
+      this.filterText.onkeyup = this.onTextChange_.bind(this);
     this.clipboardDialog = document.getElementById('clipboard-dialog');
 
     this.clipboardTextarea = document.getElementById('clipboard-textarea');
-    this.clipboardTextarea.onblur = this.hideClipboard_.bind(this);
+    if (this.clipboardTextarea)
+      this.clipboardTextarea.onblur = this.hideClipboard_.bind(this);
     var clipboardButtons = document.getElementsByClassName('copy-button');
-    for (var i = 0; i < clipboardButtons.length; i++) {
-      clipboardButtons[i].onclick = this.copyToClipboard_.bind(this);
+    if (clipboardButtons) {
+      for (var i = 0; i < clipboardButtons.length; i++) {
+        clipboardButtons[i].onclick = this.copyToClipboard_.bind(this);
+      }
     }
 
     this.saveLogButton = document.getElementById('save-log-button');
-    this.saveLogButton.onclick = this.saveLog_.bind(this);
+    if (this.saveLogButton)
+      this.saveLogButton.onclick = this.saveLog_.bind(this);
 
     this.hiddenKeys = ['component_id', 'component_type', 'owner_id'];
 
diff --git a/content/browser/resources/media/media_internals.js b/content/browser/resources/media/media_internals.js
index b285a4c..51f884e 100644
--- a/content/browser/resources/media/media_internals.js
+++ b/content/browser/resources/media/media_internals.js
@@ -11,4 +11,5 @@
 // <include src="client_renderer.js">
 
 media.initialize(new Manager(new ClientRenderer()));
-cr.ui.decorate('tabbox', cr.ui.TabBox);
+if (cr.ui)
+  cr.ui.decorate('tabbox', cr.ui.TabBox);
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm
index 158f357a..d7b18aa 100644
--- a/content/browser/sandbox_parameters_mac.mm
+++ b/content/browser/sandbox_parameters_mac.mm
@@ -11,7 +11,9 @@
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
+#include "base/numerics/checked_math.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/sys_info.h"
 #include "content/common/sandbox_mac.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
@@ -20,6 +22,25 @@
 
 namespace content {
 
+namespace {
+
+// Produce the OS version as an integer "1010", etc. and pass that to the
+// profile. The profile converts the string back to a number and can do
+// comparison operations on OS version.
+std::string GetOSVersion() {
+  int32_t major_version, minor_version, bugfix_version;
+  base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
+                                               &bugfix_version);
+  base::CheckedNumeric<int32_t> os_version(major_version);
+  os_version *= 100;
+  os_version += minor_version;
+
+  int32_t final_os_version = os_version.ValueOrDie();
+  return std::to_string(final_os_version);
+}
+
+}  // namespace
+
 void SetupRendererSandboxParameters(sandbox::SeatbeltExecClient* client) {
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
@@ -35,12 +56,7 @@
       Sandbox::GetCanonicalSandboxPath(base::GetHomeDir()).value();
   CHECK(client->SetParameter(Sandbox::kSandboxHomedirAsLiteral, homedir));
 
-  CHECK(client->SetBooleanParameter(Sandbox::kSandboxMavericks,
-                                    base::mac::IsOS10_9()));
-
-  bool elcap_or_later = base::mac::IsAtLeastOS10_11();
-  CHECK(client->SetBooleanParameter(Sandbox::kSandboxElCapOrLater,
-                                    elcap_or_later));
+  CHECK(client->SetParameter(Sandbox::kSandboxOSVersion, GetOSVersion()));
 
   std::string bundle_path =
       Sandbox::GetCanonicalSandboxPath(base::mac::MainBundlePath()).value();
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index be38010..57cefad 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -420,8 +420,8 @@
 
   // Send a second message from the interstitial page, and make sure that the
   // "evil" message doesn't arrive in the intervening period.
-  ASSERT_TRUE(ExecuteScript(interstitial_page->GetMainFrame(),
-                            "window.domAutomationController.send(\"okay2\");"));
+  ExecuteScriptAsync(interstitial_page->GetMainFrame(),
+                     "window.domAutomationController.send(\"okay2\");");
   ASSERT_TRUE(message_queue.WaitForMessage(&message));
   ASSERT_EQ("\"okay2\"", message);
   ASSERT_EQ("\"okay2\"", interstitial->last_command());
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 7a5ed8e4..08cb4e3c 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/site_instance_impl.h"
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "content/browser/browsing_instance.h"
@@ -16,6 +17,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host_factory.h"
 #include "content/public/browser/web_ui_controller_factory.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
@@ -434,6 +436,12 @@
 // static
 bool SiteInstanceImpl::ShouldLockToOrigin(BrowserContext* browser_context,
                                           GURL site_url) {
+  // Don't lock to origin in --single-process mode, since this mode puts
+  // cross-site pages into the same process.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess))
+    return false;
+
   if (!DoesSiteRequireDedicatedProcess(browser_context, site_url))
     return false;
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index ef3341d9b..1c8cab6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -2195,11 +2195,8 @@
   // Navigate the iframe itself to about:blank using a script executing in its
   // own context. It should stay in the same SiteInstance as before, not the
   // parent one.
-  std::string script(
-      "window.domAutomationController.send("
-      "window.location.href = 'about:blank');");
   TestFrameNavigationObserver frame_observer(child);
-  EXPECT_TRUE(ExecuteScript(child, script));
+  ExecuteScriptAsync(child, "window.location.href = 'about:blank';");
   frame_observer.Wait();
   EXPECT_EQ(about_blank_url, child->current_url());
 
@@ -5456,14 +5453,14 @@
       "  domAutomationController.send('%s-lost-focus');"
       "});";
   std::string script = base::StringPrintf(kSetupFocusEvents, "main", "main");
-  EXPECT_TRUE(ExecuteScript(shell(), script));
+  ExecuteScriptAsync(shell(), script);
   script = base::StringPrintf(kSetupFocusEvents, "child1", "child1");
-  EXPECT_TRUE(ExecuteScript(child1, script));
+  ExecuteScriptAsync(child1, script);
   script = base::StringPrintf(kSetupFocusEvents, "child2", "child2");
-  EXPECT_TRUE(ExecuteScript(child2, script));
+  ExecuteScriptAsync(child2, script);
 
   // Execute window.focus on the B subframe from the A main frame.
-  EXPECT_TRUE(ExecuteScript(root, "frames[0].focus()"));
+  ExecuteScriptAsync(root, "frames[0].focus()");
 
   // Helper to wait for two specified messages to arrive on the specified
   // DOMMessageQueue, assuming that the two messages can arrive in any order.
@@ -5493,7 +5490,7 @@
 
   // Now, execute window.focus on the C subframe from A main frame.  This
   // checks that we can shift focus from one remote frame to another.
-  EXPECT_TRUE(ExecuteScript(root, "frames[1].focus()"));
+  ExecuteScriptAsync(root, "frames[1].focus()");
 
   // Wait for the two subframes (B and C) to fire blur and focus events.
   wait_for_two_messages(&msg_queue, "\"child1-lost-focus\"",
@@ -5503,7 +5500,7 @@
   EXPECT_EQ(child2, root->frame_tree()->GetFocusedFrame());
 
   // window.focus the main frame from the C subframe.
-  EXPECT_TRUE(ExecuteScript(child2, "parent.focus()"));
+  ExecuteScriptAsync(child2, "parent.focus()");
 
   // Wait for the C subframe to blur and main frame to focus.
   wait_for_two_messages(&msg_queue, "\"child2-lost-focus\"",
@@ -5647,8 +5644,6 @@
         "scroll_div = document.getElementById('scrollable_div');"
         "scroll_div.addEventListener('wheel', wheel_handler);"
         "scroll_div.addEventListener('scroll', scroll_handler);"
-        "domAutomationController.setAutomationId(0);"
-        "domAutomationController.send('wheel handler installed');"
         "document.body.style.background = 'black';";
 
     content::DOMMessageQueue msg_queue;
@@ -7853,10 +7848,8 @@
 
   // Have the child frame navigate its parent to its SiteInstance.
   GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
-  std::string script = base::StringPrintf(
-      "window.domAutomationController.send("
-      "parent.location = '%s');",
-      b_url.spec().c_str());
+  std::string script =
+      base::StringPrintf("parent.location = '%s';", b_url.spec().c_str());
 
   // Ensure the child has received a user gesture, so that it has permission
   // to framebust.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index c2854649..e5c923a 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -94,7 +94,6 @@
 #include "content/public/browser/browser_plugin_guest_manager.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/download_manager.h"
-#include "content/public/browser/download_url_parameters.h"
 #include "content/public/browser/focused_node_details.h"
 #include "content/public/browser/guest_mode.h"
 #include "content/public/browser/invalidate_type.h"
@@ -122,7 +121,7 @@
 #include "content/public/common/result_codes.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/common/web_preferences.h"
-#include "device/geolocation/geolocation_service_context.h"
+#include "device/geolocation/geolocation_context.h"
 #include "net/base/url_util.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
@@ -512,7 +511,7 @@
       is_subframe_(false),
       force_disable_overscroll_content_(false),
       last_dialog_suppressed_(false),
-      geolocation_service_context_(new device::GeolocationServiceContext()),
+      geolocation_context_(new device::GeolocationContext()),
       accessibility_mode_(
           BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
       audio_stream_monitor_(this),
@@ -2647,9 +2646,8 @@
   return guest->GetMainFrame();
 }
 
-device::GeolocationServiceContext*
-WebContentsImpl::GetGeolocationServiceContext() {
-  return geolocation_service_context_.get();
+device::GeolocationContext* WebContentsImpl::GetGeolocationContext() {
+  return geolocation_context_.get();
 }
 
 device::mojom::WakeLockContext* WebContentsImpl::GetWakeLockContext() {
@@ -2922,7 +2920,18 @@
 }
 
 void WebContentsImpl::DetachInterstitialPage() {
-  // Disconnect from outer WebContents if necessary.
+  bool interstitial_pausing_throbber =
+      ShowingInterstitialPage() && interstitial_page_->pause_throbber();
+  if (ShowingInterstitialPage())
+    interstitial_page_ = nullptr;
+  for (auto& observer : observers_)
+    observer.DidDetachInterstitialPage();
+
+  // Disconnect from outer WebContents if necessary. This must happen after the
+  // interstitial page is cleared above, since the call to
+  // SetRWHViewForInnerContents below may loop over all the
+  // RenderWidgetHostViews in the tree (otherwise, including the now-deleted
+  // view for the interstitial).
   if (node_.OuterContentsFrameTreeNode()) {
     if (GetRenderManager()->GetProxyToOuterDelegate()) {
       DCHECK(static_cast<RenderWidgetHostViewBase*>(
@@ -2935,13 +2944,6 @@
     }
   }
 
-  bool interstitial_pausing_throbber =
-      ShowingInterstitialPage() && interstitial_page_->pause_throbber();
-  if (ShowingInterstitialPage())
-    interstitial_page_ = nullptr;
-  for (auto& observer : observers_)
-    observer.DidDetachInterstitialPage();
-
   // Restart the throbber if needed now that the interstitial page is going
   // away.
   if (interstitial_pausing_throbber && frame_tree_.IsLoading())
@@ -3275,12 +3277,9 @@
   if (headers.empty()) {
     params->set_prefer_cache(true);
   } else {
-    for (const base::StringPiece& key_value : base::SplitStringPiece(
-             headers, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
-      std::vector<std::string> pair = base::SplitString(
-          key_value, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-      DCHECK_EQ(2ul, pair.size());
-      params->add_request_header(pair[0], pair[1]);
+    for (DownloadUrlParameters::RequestHeadersNameValuePair key_value :
+         ParseDownloadHeaders(headers)) {
+      params->add_request_header(key_value.first, key_value.second);
     }
   }
   BrowserContext::GetDownloadManager(GetBrowserContext())
@@ -5835,6 +5834,19 @@
     render_view_host->OnWebkitPreferencesChanged();
 }
 
+DownloadUrlParameters::RequestHeadersType WebContentsImpl::ParseDownloadHeaders(
+    const std::string& headers) {
+  DownloadUrlParameters::RequestHeadersType request_headers;
+  for (const base::StringPiece& key_value : base::SplitStringPiece(
+           headers, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+    std::vector<std::string> pair = base::SplitString(
+        key_value, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    if (2ul == pair.size())
+      request_headers.push_back(make_pair(pair[0], pair[1]));
+  }
+  return request_headers;
+}
+
 void WebContentsImpl::SetOpenerForNewContents(FrameTreeNode* opener,
                                               bool opener_suppressed) {
   if (opener) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index d897b52..e16ba9d 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -35,6 +35,7 @@
 #include "content/common/accessibility_mode.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/color_chooser.h"
+#include "content/public/browser/download_url_parameters.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents.h"
@@ -523,7 +524,7 @@
   RenderFrameHost* GetGuestByInstanceID(
       RenderFrameHost* render_frame_host,
       int browser_plugin_instance_id) override;
-  device::GeolocationServiceContext* GetGeolocationServiceContext() override;
+  device::GeolocationContext* GetGeolocationContext() override;
   device::mojom::WakeLockContext* GetWakeLockContext() override;
   device::mojom::WakeLock* GetRendererWakeLock() override;
 #if defined(OS_ANDROID)
@@ -913,6 +914,7 @@
                            LoadResourceWithEmptySecurityInfo);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest,
                            ResetJavaScriptDialogOnUserNavigate);
+  FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest, ParseDownloadHeaders);
   FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
   FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
   FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
@@ -1295,6 +1297,11 @@
   // an IPC to all the renderer process associated with this WebContents.
   void NotifyPreferencesChanged();
 
+  // Format of |headers| is a new line separated list of key value pairs:
+  // "<key1>: <value1>\r\n<key2>: <value2>".
+  static DownloadUrlParameters::RequestHeadersType ParseDownloadHeaders(
+      const std::string& headers);
+
   // Data for core operation ---------------------------------------------------
 
   // Delegate for notifying our owner about stuff. Not owned by us.
@@ -1571,8 +1578,7 @@
   // Whether the last JavaScript dialog shown was suppressed. Used for testing.
   bool last_dialog_suppressed_;
 
-  std::unique_ptr<device::GeolocationServiceContext>
-      geolocation_service_context_;
+  std::unique_ptr<device::GeolocationContext> geolocation_context_;
 
   std::unique_ptr<WakeLockContextHost> wake_lock_context_host_;
 
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 7dbe246..378075df 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -27,6 +27,7 @@
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/download_url_parameters.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/interstitial_page_delegate.h"
 #include "content/public/browser/javascript_dialog_manager.h"
@@ -3485,6 +3486,38 @@
   DeleteContents();
 }
 
+TEST_F(WebContentsImplTest, ParseDownloadHeaders) {
+  DownloadUrlParameters::RequestHeadersType request_headers =
+      WebContentsImpl::ParseDownloadHeaders("A: 1\r\nB: 2\r\nC: 3\r\n\r\n");
+  ASSERT_EQ(3u, request_headers.size());
+  EXPECT_EQ("A", request_headers[0].first);
+  EXPECT_EQ("1", request_headers[0].second);
+  EXPECT_EQ("B", request_headers[1].first);
+  EXPECT_EQ("2", request_headers[1].second);
+  EXPECT_EQ("C", request_headers[2].first);
+  EXPECT_EQ("3", request_headers[2].second);
+
+  request_headers = WebContentsImpl::ParseDownloadHeaders("A:1\r\nA:2\r\n");
+  ASSERT_EQ(2u, request_headers.size());
+  EXPECT_EQ("A", request_headers[0].first);
+  EXPECT_EQ("1", request_headers[0].second);
+  EXPECT_EQ("A", request_headers[1].first);
+  EXPECT_EQ("2", request_headers[1].second);
+
+  request_headers = WebContentsImpl::ParseDownloadHeaders("A 1\r\nA: 2");
+  ASSERT_EQ(1u, request_headers.size());
+  EXPECT_EQ("A", request_headers[0].first);
+  EXPECT_EQ("2", request_headers[0].second);
+
+  request_headers = WebContentsImpl::ParseDownloadHeaders("A: 1");
+  ASSERT_EQ(1u, request_headers.size());
+  EXPECT_EQ("A", request_headers[0].first);
+  EXPECT_EQ("1", request_headers[0].second);
+
+  request_headers = WebContentsImpl::ParseDownloadHeaders("A 1");
+  ASSERT_EQ(0u, request_headers.size());
+}
+
 namespace {
 
 class TestJavaScriptDialogManager : public JavaScriptDialogManager {
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 9cd07123..3167829 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -534,8 +534,7 @@
 
 // Disabled because the test always fails the first time it runs on the Win Aura
 // bots, and usually but not always passes second-try (See crbug.com/179532).
-// On Linux, the test frequently times out. (See crbug.com/440043).
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN)
 #define MAYBE_QuickOverscrollDirectionChange \
         DISABLED_QuickOverscrollDirectionChange
 #else
@@ -565,6 +564,10 @@
   ui::EventSink* sink = content->GetHost()->event_sink();
   gfx::Rect bounds = content->GetBoundsInRootWindow();
 
+  // Spurious mouse moves interfere with the overscroll gesture which causes
+  // this test to fail. This observer will let us know if this is happening.
+  SpuriousMouseMoveEventObserver mouse_observer(GetRenderWidgetHost());
+
   base::TimeTicks timestamp = ui::EventTimeForNow();
   ui::TouchEvent press(
       ui::ET_TOUCH_PRESSED,
diff --git a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index 008ee47f..7422017 100644
--- a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -98,7 +98,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
-                       VerifyCanvasCaptureWebGLFrames) {
+                       DISABLED_VerifyCanvasCaptureWebGLFrames) {
   MakeTypicalCall("testCanvasCapture(drawWebGL);", kCanvasCaptureTestHtmlFile);
 }
 
diff --git a/content/common/sandbox_mac.h b/content/common/sandbox_mac.h
index f4dde38..7d5f9f7 100644
--- a/content/common/sandbox_mac.h
+++ b/content/common/sandbox_mac.h
@@ -51,8 +51,7 @@
   static const char* kSandboxEnableLogging;
   static const char* kSandboxDisableDenialLogging;
   static const char* kSandboxHomedirAsLiteral;
-  static const char* kSandboxElCapOrLater;
-  static const char* kSandboxMavericks;
+  static const char* kSandboxOSVersion;
   static const char* kSandboxPermittedDir;
   static const char* kSandboxBundlePath;
   static const char* kSandboxLoggingPathAsLiteral;
@@ -60,6 +59,9 @@
   static const char* kSandboxComponentPath;
   static const char* kSandboxChromePID;
 
+  // TODO(kerrnel): this is only for the legacy sandbox.
+  static const char* kSandboxElCapOrLater;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(MacDirAccessSandboxTest, StringEscape);
   FRIEND_TEST_ALL_PREFIXES(MacDirAccessSandboxTest, RegexEscape);
diff --git a/content/common/sandbox_mac.mm b/content/common/sandbox_mac.mm
index cfe004f..570edc5 100644
--- a/content/common/sandbox_mac.mm
+++ b/content/common/sandbox_mac.mm
@@ -72,14 +72,14 @@
 const char* Sandbox::kSandboxDisableDenialLogging =
     "DISABLE_SANDBOX_DENIAL_LOGGING";
 const char* Sandbox::kSandboxHomedirAsLiteral = "USER_HOMEDIR_AS_LITERAL";
-const char* Sandbox::kSandboxElCapOrLater = "ELCAP_OR_LATER";
-const char* Sandbox::kSandboxMavericks = "IS_MAVERICKS";
+const char* Sandbox::kSandboxOSVersion = "OS_VERSION";
 const char* Sandbox::kSandboxPermittedDir = "PERMITTED_DIR";
 const char* Sandbox::kSandboxBundlePath = "BUNDLE_PATH";
 const char* Sandbox::kSandboxLoggingPathAsLiteral = "LOG_FILE_PATH";
 const char* Sandbox::kSandboxChromeBundleId = "BUNDLE_ID";
 const char* Sandbox::kSandboxComponentPath = "COMPONENT_PATH";
 const char* Sandbox::kSandboxChromePID = "CHROMIUM_PID";
+const char* Sandbox::kSandboxElCapOrLater = "ELCAP_OR_LATER";
 
 // Warm up System APIs that empirically need to be accessed before the Sandbox
 // is turned on.
diff --git a/content/common/site_isolation_policy.cc b/content/common/site_isolation_policy.cc
index 7fa66c2..3fc8ba5f 100644
--- a/content/common/site_isolation_policy.cc
+++ b/content/common/site_isolation_policy.cc
@@ -6,7 +6,6 @@
 
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 
@@ -14,17 +13,7 @@
 
 // static
 bool SiteIsolationPolicy::AreCrossProcessFramesPossible() {
-// Before turning this on for Android, input event routing needs to be
-// completed there, and perf regressions in https://crbug.com/690229 need to be
-// investigated.
-#if defined(OS_ANDROID)
-  return UseDedicatedProcessesForAllSites() ||
-         IsTopDocumentIsolationEnabled() || AreIsolatedOriginsEnabled() ||
-         GetContentClient()->IsSupplementarySiteIsolationModeEnabled() ||
-         base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames);
-#else
   return true;
-#endif
 }
 
 // static
diff --git a/content/network/network_service.cc b/content/network/network_service.cc
index a133884..a9a8845 100644
--- a/content/network/network_service.cc
+++ b/content/network/network_service.cc
@@ -7,11 +7,12 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/values.h"
 #include "content/network/network_context.h"
 #include "content/public/common/content_switches.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/log/file_net_log_observer.h"
 #include "net/log/net_log_util.h"
-#include "net/log/write_to_file_net_log_observer.h"
 #include "services/service_manager/public/cpp/bind_source_info.h"
 
 namespace content {
@@ -21,34 +22,27 @@
   MojoNetLog() {
     const base::CommandLine* command_line =
         base::CommandLine::ForCurrentProcess();
-    if (!command_line->HasSwitch(switches::kLogNetLog))
-      return;
-    base::FilePath log_path =
-        command_line->GetSwitchValuePath(switches::kLogNetLog);
-    base::ScopedFILE file;
-#if defined(OS_WIN)
-    file.reset(_wfopen(log_path.value().c_str(), L"w"));
-#elif defined(OS_POSIX)
-    file.reset(fopen(log_path.value().c_str(), "w"));
-#endif
-    if (!file) {
-      LOG(ERROR) << "Could not open file " << log_path.value()
-                 << " for net logging";
-    } else {
-      write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
-      write_to_file_observer_->set_capture_mode(
-          net::NetLogCaptureMode::IncludeCookiesAndCredentials());
-      write_to_file_observer_->StartObserving(this, std::move(file), nullptr,
-                                              nullptr);
+
+    // If specified by the command line, stream network events (NetLog) to a
+    // file on disk. This will last for the duration of the process.
+    if (command_line->HasSwitch(switches::kLogNetLog)) {
+      base::FilePath log_path =
+          command_line->GetSwitchValuePath(switches::kLogNetLog);
+      net::NetLogCaptureMode capture_mode =
+          net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+
+      file_net_log_observer_ =
+          net::FileNetLogObserver::CreateUnbounded(log_path, nullptr);
+      file_net_log_observer_->StartObserving(this, capture_mode);
     }
   }
   ~MojoNetLog() override {
-    if (write_to_file_observer_)
-      write_to_file_observer_->StopObserving(nullptr);
+    if (file_net_log_observer_)
+      file_net_log_observer_->StopObserving(nullptr, base::OnceClosure());
   }
 
  private:
-  std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
+  std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
   DISALLOW_COPY_AND_ASSIGN(MojoNetLog);
 };
 
diff --git a/content/public/android/java/src/org/chromium/content/app/ChromiumLinkerParams.java b/content/public/android/java/src/org/chromium/content/app/ChromiumLinkerParams.java
index ca11013..304b383 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChromiumLinkerParams.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChromiumLinkerParams.java
@@ -4,8 +4,7 @@
 
 package org.chromium.content.app;
 
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.Bundle;
 
 import java.util.Locale;
 
@@ -17,7 +16,7 @@
  * technical notes in Linker.java.
  */
 @Immutable
-public class ChromiumLinkerParams implements Parcelable {
+public class ChromiumLinkerParams {
     // Use this base address to load native shared libraries. If 0, ignore other members.
     public final long mBaseLoadAddress;
 
@@ -32,6 +31,18 @@
     // to force for testing.
     public final int mLinkerImplementationForTesting;
 
+    private static final String EXTRA_LINKER_PARAMS_BASE_LOAD_ADDRESS =
+            "org.chromium.content.common.linker_params.base_load_address";
+
+    private static final String EXTRA_LINKER_PARAMS_WAIT_FOR_SHARED_RELRO =
+            "org.chromium.content.common.linker_params.wait_for_shared_relro";
+
+    private static final String EXTRA_LINKER_PARAMS_TEST_RUNNER_CLASS_NAME =
+            "org.chromium.content.common.linker_params.test_runner_class_name";
+
+    private static final String EXTRA_LINKER_PARAMS_LINKER_IMPLEMENTATION =
+            "org.chromium.content.common.linker_params.linker_implementation";
+
     public ChromiumLinkerParams(long baseLoadAddress, boolean waitForSharedRelro) {
         mBaseLoadAddress = baseLoadAddress;
         mWaitForSharedRelro = waitForSharedRelro;
@@ -52,39 +63,45 @@
         mLinkerImplementationForTesting = linkerImplementation;
     }
 
-    ChromiumLinkerParams(Parcel in) {
-        mBaseLoadAddress = in.readLong();
-        mWaitForSharedRelro = in.readInt() != 0;
-        mTestRunnerClassNameForTesting = in.readString();
-        mLinkerImplementationForTesting = in.readInt();
+    /**
+     * Use this method to recreate a LinkerParams instance from a Bundle.
+     *
+     * @param bundle A Bundle, its content must have been populated by a previous
+     * call to populateBundle().
+     * @return params instance or possibly null if params was not put into bundle.
+     */
+    public static ChromiumLinkerParams create(Bundle bundle) {
+        if (!bundle.containsKey(EXTRA_LINKER_PARAMS_BASE_LOAD_ADDRESS)
+                || !bundle.containsKey(EXTRA_LINKER_PARAMS_WAIT_FOR_SHARED_RELRO)
+                || !bundle.containsKey(EXTRA_LINKER_PARAMS_TEST_RUNNER_CLASS_NAME)
+                || !bundle.containsKey(EXTRA_LINKER_PARAMS_LINKER_IMPLEMENTATION)) {
+            return null;
+        }
+        return new ChromiumLinkerParams(bundle);
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    private ChromiumLinkerParams(Bundle bundle) {
+        mBaseLoadAddress = bundle.getLong(EXTRA_LINKER_PARAMS_BASE_LOAD_ADDRESS, 0);
+        mWaitForSharedRelro = bundle.getBoolean(EXTRA_LINKER_PARAMS_WAIT_FOR_SHARED_RELRO, false);
+        mTestRunnerClassNameForTesting =
+                bundle.getString(EXTRA_LINKER_PARAMS_TEST_RUNNER_CLASS_NAME);
+        mLinkerImplementationForTesting =
+                bundle.getInt(EXTRA_LINKER_PARAMS_LINKER_IMPLEMENTATION, 0);
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(mBaseLoadAddress);
-        dest.writeInt(mWaitForSharedRelro ? 1 : 0);
-        dest.writeString(mTestRunnerClassNameForTesting);
-        dest.writeInt(mLinkerImplementationForTesting);
+    /**
+     * Save data in this LinkerParams instance in a bundle, to be sent to a service process.
+     *
+     * @param bundle An bundle to be passed to the child service process.
+     */
+    public void populateBundle(Bundle bundle) {
+        bundle.putLong(EXTRA_LINKER_PARAMS_BASE_LOAD_ADDRESS, mBaseLoadAddress);
+        bundle.putBoolean(EXTRA_LINKER_PARAMS_WAIT_FOR_SHARED_RELRO, mWaitForSharedRelro);
+        bundle.putString(
+                EXTRA_LINKER_PARAMS_TEST_RUNNER_CLASS_NAME, mTestRunnerClassNameForTesting);
+        bundle.putInt(EXTRA_LINKER_PARAMS_LINKER_IMPLEMENTATION, mLinkerImplementationForTesting);
     }
 
-    public static final Parcelable.Creator<ChromiumLinkerParams> CREATOR =
-            new Parcelable.Creator<ChromiumLinkerParams>() {
-                @Override
-                public ChromiumLinkerParams createFromParcel(Parcel in) {
-                    return new ChromiumLinkerParams(in);
-                }
-
-                @Override
-                public ChromiumLinkerParams[] newArray(int size) {
-                    return new ChromiumLinkerParams[size];
-                }
-            };
-
     // For debugging traces only.
     @Override
     public String toString() {
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
index 2cc9ea4..c55cc361 100644
--- a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
@@ -64,8 +64,7 @@
 
     @Override
     public void onServiceBound(Intent intent) {
-        mLinkerParams = (ChromiumLinkerParams) intent.getParcelableExtra(
-                ContentChildProcessConstants.EXTRA_LINKER_PARAMS);
+        mLinkerParams = ChromiumLinkerParams.create(intent.getExtras());
         mLibraryProcessType = ChildProcessCreationParams.getLibraryProcessType(intent);
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
index 9e4204a..11b4896d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -515,8 +515,8 @@
         boolean bindToCallerCheck =
                 creationParams == null ? false : creationParams.getBindToCallerCheck();
         bundle.putBoolean(ChildProcessConstants.EXTRA_BIND_TO_CALLER, bindToCallerCheck);
-        bundle.putParcelable(ContentChildProcessConstants.EXTRA_LINKER_PARAMS,
-                getLinkerParamsForNewConnection());
+        ChromiumLinkerParams linkerParams = getLinkerParamsForNewConnection();
+        if (linkerParams != null) linkerParams.populateBundle(bundle);
         return bundle;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentChildProcessConstants.java b/content/public/android/java/src/org/chromium/content/browser/ContentChildProcessConstants.java
index 77607e3..8dd2fb6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentChildProcessConstants.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentChildProcessConstants.java
@@ -12,10 +12,6 @@
     // Note that because that intent maybe reused if a service is restarted, none should be process
     // specific.
 
-    // Key in the binding Intent's Bundle for the ChromiumLinkerParams.
-    public static final String EXTRA_LINKER_PARAMS =
-            "com.google.android.apps.chrome.extra.linker_params";
-
     // Below are the names for the items placed in the Bundle passed in the
     // IChildProcessService.setupConnection call, once the connection has been established.
 
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 fafdcbd3..d4af7a5 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
@@ -506,6 +506,15 @@
         mSelectionPopupController.setCallback(callback);
     }
 
+    /**
+     * Set {@link ActionMode.Callback} used by {@link SelectionPopupController} when no text is
+     * selected.
+     * @param callback ActionMode.Callback instance.
+     */
+    public void setNonSelectionActionModeCallback(ActionMode.Callback callback) {
+        mSelectionPopupController.setNonSelectionCallback(callback);
+    }
+
     private void addDisplayAndroidObserverIfNeeded() {
         if (!mAttachedToWindow) return;
         WindowAndroid windowAndroid = getWindowAndroid();
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
index 9d5b71a..891806a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -93,6 +93,9 @@
     private final RenderCoordinates mRenderCoordinates;
     private ActionMode.Callback mCallback;
 
+    // Used to customize PastePopupMenu
+    private ActionMode.Callback mNonSelectionCallback;
+
     // Selection rectangle in DIP.
     private final Rect mSelectionRect = new Rect();
 
@@ -205,6 +208,10 @@
         mCallback = callback;
     }
 
+    void setNonSelectionCallback(ActionMode.Callback callback) {
+        mNonSelectionCallback = callback;
+    }
+
     @Override
     public boolean isActionModeValid() {
         return mActionMode != null;
@@ -296,7 +303,7 @@
             return;
         }
 
-        if (!supportsFloatingActionMode() && !canPaste()) return;
+        if (!supportsFloatingActionMode() && !canPaste() && mNonSelectionCallback == null) return;
         destroyPastePopup();
         PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() {
             @Override
@@ -334,7 +341,8 @@
         Context windowContext = mWindowAndroid.getContext().get();
         if (windowContext == null) return;
         if (supportsFloatingActionMode()) {
-            mPastePopupMenu = new FloatingPastePopupMenu(windowContext, mView, delegate);
+            mPastePopupMenu = new FloatingPastePopupMenu(
+                    windowContext, mView, delegate, mNonSelectionCallback);
         } else {
             mPastePopupMenu = new LegacyPastePopupMenu(windowContext, mView, delegate);
         }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java b/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
index 3b1e23b..2a221fa 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/FloatingPastePopupMenu.java
@@ -28,13 +28,16 @@
 
     private ActionMode mActionMode;
     private Rect mSelectionRect;
+    private ActionMode.Callback mExternalCallback;
 
-    public FloatingPastePopupMenu(Context context, View parent, PastePopupMenuDelegate delegate) {
+    public FloatingPastePopupMenu(Context context, View parent, PastePopupMenuDelegate delegate,
+            ActionMode.Callback externalCallback) {
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
 
         mParent = parent;
         mDelegate = delegate;
         mContext = context;
+        mExternalCallback = externalCallback;
     }
 
     @Override
@@ -74,6 +77,7 @@
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             createPasteMenu(mode, menu);
+            if (mExternalCallback != null) mExternalCallback.onCreateActionMode(mode, menu);
             return true;
         }
 
@@ -102,29 +106,35 @@
 
         @Override
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-            return false;
+            boolean ret = false;
+            if (mExternalCallback != null) {
+                ret = mExternalCallback.onPrepareActionMode(mode, menu);
+            }
+            return ret;
         }
 
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
             int id = item.getItemId();
+            boolean ret = true;
             if (id == R.id.select_action_menu_paste) {
                 mDelegate.paste();
                 mode.finish();
-            }
-            if (id == R.id.select_action_menu_paste_as_plain_text) {
+            } else if (id == R.id.select_action_menu_paste_as_plain_text) {
                 mDelegate.pasteAsPlainText();
                 mode.finish();
-            }
-            if (id == R.id.select_action_menu_select_all) {
+            } else if (id == R.id.select_action_menu_select_all) {
                 mDelegate.selectAll();
                 mode.finish();
+            } else if (mExternalCallback != null) {
+                ret = mExternalCallback.onActionItemClicked(mode, item);
             }
-            return true;
+            return ret;
         }
 
         @Override
         public void onDestroyActionMode(ActionMode mode) {
+            if (mExternalCallback != null) mExternalCallback.onDestroyActionMode(mode);
             mActionMode = null;
         }
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index 5ff7ab2..727c612 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -507,6 +507,9 @@
         Assert.assertNull(createChildProcessLauncher(mConnectionAllocator,
                 true /* setupConnection */, false /* queueIfNoFreeConnection */));
 
+        waitForConnectionState(connections[0], CONNECTION_BLOCK_UNTIL_SETUP);
+        waitForConnectionState(connections[1], CONNECTION_BLOCK_UNTIL_SETUP);
+
         // Stop one connection, that should free-up a connection and the first queued launcher
         // should use it.
         stopLauncher(launchers[0]);
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 820f611..ab5e08d 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -106,7 +106,7 @@
           "content::mojom::BrowserTarget",
           "content::mojom::RendererAudioOutputStreamFactory",
           "device::mojom::VRService",
-          "device::mojom::GeolocationService",
+          "device::mojom::Geolocation",
           "device::mojom::NFC",
           "device::mojom::WakeLock",
           "device::usb::DeviceManager",
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index bd99766..25ddd4c 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -248,7 +248,6 @@
   IPC_STRUCT_TRAITS_MEMBER(default_maximum_page_scale_factor)
   IPC_STRUCT_TRAITS_MEMBER(hide_download_ui)
   IPC_STRUCT_TRAITS_MEMBER(background_video_track_optimization_enabled)
-  IPC_STRUCT_TRAITS_MEMBER(enable_instant_source_buffer_gc)
   IPC_STRUCT_TRAITS_MEMBER(presentation_receiver)
   IPC_STRUCT_TRAITS_MEMBER(media_controls_enabled)
   IPC_STRUCT_TRAITS_MEMBER(do_not_update_selection_on_mutating_selection_range)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 6a0e423..5409b6dd 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -720,6 +720,9 @@
 // renderer process.  We default to using a renderer process for each
 // site instance (i.e., group of pages from the same registered domain with
 // script connections to each other).
+// TODO(creis): This flag is currently a no-op.  We should refactor it to avoid
+// "unnecessary" process swaps for cross-site navigations but still swap when
+// needed for security (e.g., isolated origins).
 const char kProcessPerTab[]                 = "process-per-tab";
 
 // The value of this switch determines whether the process is started as a
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 2646681..68d5e488 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -219,7 +219,6 @@
 #endif
       hide_download_ui(false),
       background_video_track_optimization_enabled(false),
-      enable_instant_source_buffer_gc(false),
       presentation_receiver(false),
       media_controls_enabled(true),
       do_not_update_selection_on_mutating_selection_range(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 3332863..0a275a92 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -267,14 +267,6 @@
   // If enabled, disabled video track when the video is in the background.
   bool background_video_track_optimization_enabled;
 
-  // When memory pressure based garbage collection is enabled for MSE, the
-  // |enable_instant_source_buffer_gc| flag controls whether the GC is done
-  // immediately on memory pressure notification or during the next SourceBuffer
-  // append (slower, but is MSE-spec compliant).
-  // TODO(servolk, asvitkine): Query the value directly when it is available in
-  // the renderer process. See https://crbug.com/681160.
-  bool enable_instant_source_buffer_gc;
-
   // Whether it is a presentation receiver.
   bool presentation_receiver;
 
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index b88b61ff..725456c3 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/macros.h"
 #include "base/process/kill.h"
@@ -20,6 +21,7 @@
 #include "base/strings/pattern.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
@@ -175,6 +177,36 @@
   return true;
 }
 
+bool ExecuteScriptWithUserGestureControl(RenderFrameHost* frame,
+                                         const std::string& script,
+                                         bool user_gesture) {
+  // TODO(lukasza): ExecuteScript should just call
+  // ExecuteJavaScriptWithUserGestureForTests and avoid modifying the original
+  // script (and at that point we should merge it with and remove
+  // ExecuteScriptAsync).  This is difficult to change, because many tests
+  // depend on the message loop pumping done by ExecuteScriptHelper below (this
+  // is fragile - these tests should wait on a more specific thing instead).
+
+  std::string expected_response = "ExecuteScript-" + base::GenerateGUID();
+  std::string new_script = base::StringPrintf(
+      R"( %s;  // Original script.
+          window.domAutomationController.send('%s'); )",
+      script.c_str(), expected_response.c_str());
+
+  std::unique_ptr<base::Value> value;
+  if (!ExecuteScriptHelper(frame, new_script, user_gesture, &value) ||
+      !value.get()) {
+    return false;
+  }
+
+  DCHECK_EQ(base::Value::Type::STRING, value->GetType());
+  std::string actual_response;
+  if (value->GetAsString(&actual_response))
+    DCHECK_EQ(expected_response, actual_response);
+
+  return true;
+}
+
 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
 bool ExecuteScriptInIsolatedWorldHelper(RenderFrameHost* render_frame_host,
                                         const int world_id,
@@ -414,19 +446,18 @@
 //
 // Returns has-video-input-device to the test if there is a webcam available,
 // no-video-input-devices otherwise.
-const char kHasVideoInputDeviceOnSystem[] =
-    "(function() {"
-      "navigator.mediaDevices.enumerateDevices()"
-      ".then(function(devices) {"
-        "devices.forEach(function(device) {"
-          "if (device.kind == 'videoinput') {"
-            "window.domAutomationController.send('has-video-input-device');"
-            "return;"
-          "}"
-        "});"
-        "window.domAutomationController.send('no-video-input-devices');"
-      "});"
-    "})()";
+const char kHasVideoInputDeviceOnSystem[] = R"(
+    (function() {
+      navigator.mediaDevices.enumerateDevices()
+      .then(function(devices) {
+        if (devices.some((device) => device.kind == 'videoinput')) {
+          window.domAutomationController.send('has-video-input-device');
+        } else {
+          window.domAutomationController.send('no-video-input-devices');
+        }
+      });
+    })()
+)";
 
 const char kHasVideoInputDevice[] = "has-video-input-device";
 
@@ -817,17 +848,20 @@
 
 bool ExecuteScript(const ToRenderFrameHost& adapter,
                    const std::string& script) {
-  std::string new_script =
-      script + ";window.domAutomationController.send(0);";
-  return ExecuteScriptHelper(adapter.render_frame_host(), new_script, true,
-                             nullptr);
+  return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
+                                             script, true);
 }
 
 bool ExecuteScriptWithoutUserGesture(const ToRenderFrameHost& adapter,
                                      const std::string& script) {
-  std::string new_script = script + ";window.domAutomationController.send(0);";
-  return ExecuteScriptHelper(adapter.render_frame_host(), new_script, false,
-                             nullptr);
+  return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
+                                             script, false);
+}
+
+void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
+                        const std::string& script) {
+  adapter.render_frame_host()->ExecuteJavaScriptWithUserGestureForTests(
+      base::UTF8ToUTF16(script));
 }
 
 bool ExecuteScriptAndExtractDouble(const ToRenderFrameHost& adapter,
@@ -1000,12 +1034,10 @@
 
     script.append("\n");
   }
-  if (!ExecuteScript(web_contents, script))
-    return false;
+  ExecuteScriptAsync(web_contents, script);
 
   DOMMessageQueue message_queue;
-  if (!ExecuteScript(web_contents, "runTests()"))
-    return false;
+  ExecuteScriptAsync(web_contents, "runTests()");
 
   std::string message;
   do {
@@ -1493,7 +1525,7 @@
                               const NotificationDetails& details) {
   Details<std::string> dom_op_result(details);
   message_queue_.push(*dom_op_result.ptr());
-  if (message_loop_runner_.get())
+  if (message_loop_runner_)
     message_loop_runner_->Quit();
 }
 
@@ -1504,6 +1536,7 @@
     case base::TERMINATION_STATUS_STILL_RUNNING:
       break;
     default:
+      renderer_crashed_ = true;
       if (message_loop_runner_.get())
         message_loop_runner_->Quit();
       break;
@@ -1516,7 +1549,7 @@
 
 bool DOMMessageQueue::WaitForMessage(std::string* message) {
   DCHECK(message);
-  if (message_queue_.empty()) {
+  if (!renderer_crashed_ && message_queue_.empty()) {
     // This will be quit when a new message comes in.
     message_loop_runner_ =
         new MessageLoopRunner(MessageLoopRunner::QuitMode::IMMEDIATE);
@@ -1527,7 +1560,7 @@
 
 bool DOMMessageQueue::PopMessage(std::string* message) {
   DCHECK(message);
-  if (message_queue_.empty())
+  if (renderer_crashed_ || message_queue_.empty())
     return false;
   *message = message_queue_.front();
   message_queue_.pop();
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index da139cd..cb6cb488 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -207,9 +207,23 @@
 RenderFrameHost* ConvertToRenderFrameHost(WebContents* web_contents);
 
 // Executes the passed |script| in the specified frame with the user gesture.
-// The |script| should not invoke domAutomationController.send(); otherwise,
-// your test will hang or be flaky. If you want to extract a result, use one of
-// the below functions. Returns true on success.
+//
+// Appends |domAutomationController.send(...)| to the end of |script| and waits
+// until the response comes back (pumping the message loop while waiting).  The
+// |script| itself should not invoke domAutomationController.send(); if you want
+// to call domAutomationController.send(...) yourself and extract the result,
+// then use one of ExecuteScriptAndExtract... functions).
+//
+// Returns true on success (if the renderer responded back with the expected
+// value).  Returns false otherwise (e.g. if the script threw an exception
+// before calling the appended |domAutomationController.send(...)|, or if the
+// renderer died or if the renderer called |domAutomationController.send(...)|
+// with a malformed or unexpected value).
+//
+// See also:
+// - ExecuteScriptAsync
+// - ExecuteScriptAndExtractBool/Int/String/etc.
+// - DOMMessageQueue (to manually wait for domAutomationController.send(...))
 bool ExecuteScript(const ToRenderFrameHost& adapter,
                    const std::string& script) WARN_UNUSED_RESULT;
 
@@ -219,11 +233,18 @@
                                      const std::string& script)
     WARN_UNUSED_RESULT;
 
-// The following methods execute the passed |script| in the specified frame with
-// the user gesture and set |result| to the value passed to
-// "window.domAutomationController.send" by the executed script. They return
-// true on success, false if the script execution failed or did not evaluate to
-// the expected type.
+// Similar to ExecuteScript above, but
+// - Doesn't modify the |script|.
+// - Kicks off execution of the |script| in the specified frame and returns
+//   immediately (without waiting for a response from the renderer and/or
+//   without checking that the script succeeded).
+void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
+                        const std::string& script);
+
+// The following methods execute the passed |script| in the specified frame and
+// sets |result| to the value passed to "window.domAutomationController.send" by
+// the executed script. They return true on success, false if the script
+// execution failed or did not evaluate to the expected type.
 bool ExecuteScriptAndExtractDouble(const ToRenderFrameHost& adapter,
                                    const std::string& script,
                                    double* result) WARN_UNUSED_RESULT;
@@ -521,6 +542,7 @@
   NotificationRegistrar registrar_;
   std::queue<std::string> message_queue_;
   scoped_refptr<MessageLoopRunner> message_loop_runner_;
+  bool renderer_crashed_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DOMMessageQueue);
 };
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index 93126e8..7d13e18 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -9,6 +9,7 @@
   "+components/url_formatter",
   "+components/variations",
   "+components/viz/client",
+  "+components/viz/common/resources",
 
   "+cc/blink",
   "+content/public/child",
diff --git a/content/renderer/dom_automation_controller.cc b/content/renderer/dom_automation_controller.cc
index 7973ba4e..e3d3504 100644
--- a/content/renderer/dom_automation_controller.cc
+++ b/content/renderer/dom_automation_controller.cc
@@ -42,7 +42,7 @@
 }
 
 DomAutomationController::DomAutomationController(RenderFrame* render_frame)
-    : RenderFrameObserver(render_frame), automation_id_(MSG_ROUTING_NONE) {}
+    : RenderFrameObserver(render_frame) {}
 
 DomAutomationController::~DomAutomationController() {}
 
@@ -84,9 +84,6 @@
   if (!render_frame())
     return false;
 
-  if (automation_id_ == MSG_ROUTING_NONE)
-    return false;
-
   std::string json;
   JSONStringValueSerializer serializer(&json);
   std::unique_ptr<base::Value> value;
@@ -112,7 +109,6 @@
   bool succeeded = Send(new FrameHostMsg_DomOperationResponse(
       routing_id(), json));
 
-  automation_id_ = MSG_ROUTING_NONE;
   return succeeded;
 }
 
@@ -120,12 +116,9 @@
   if (!render_frame())
     return false;
 
-  if (automation_id_ == MSG_ROUTING_NONE)
-    return false;
   bool result = Send(new FrameHostMsg_DomOperationResponse(
       routing_id(), json));
 
-  automation_id_ = MSG_ROUTING_NONE;
   return result;
 }
 
@@ -138,7 +131,6 @@
 }
 
 bool DomAutomationController::SetAutomationId(int automation_id) {
-  automation_id_ = automation_id;
   return true;
 }
 
diff --git a/content/renderer/dom_automation_controller.h b/content/renderer/dom_automation_controller.h
index 8742ec40..0db719f5 100644
--- a/content/renderer/dom_automation_controller.h
+++ b/content/renderer/dom_automation_controller.h
@@ -120,8 +120,6 @@
   void DidCreateScriptContext(v8::Local<v8::Context> context,
                               int world_id) override;
 
-  int automation_id_;  // routing id to be used by the next channel.
-
   DISALLOW_COPY_AND_ASSIGN(DomAutomationController);
 };
 
diff --git a/content/renderer/gpu/compositor_dependencies.h b/content/renderer/gpu/compositor_dependencies.h
index 05e6bf5d..38503df 100644
--- a/content/renderer/gpu/compositor_dependencies.h
+++ b/content/renderer/gpu/compositor_dependencies.h
@@ -38,7 +38,8 @@
   virtual bool IsPartialRasterEnabled() = 0;
   virtual bool IsGpuMemoryBufferCompositorResourcesEnabled() = 0;
   virtual bool IsElasticOverscrollEnabled() = 0;
-  virtual const cc::BufferToTextureTargetMap& GetBufferToTextureTargetMap() = 0;
+  virtual const viz::BufferToTextureTargetMap&
+  GetBufferToTextureTargetMap() = 0;
   virtual scoped_refptr<base::SingleThreadTaskRunner>
   GetCompositorMainThreadTaskRunner() = 0;
   // Returns null if the compositor is in single-threaded mode (ie. there is no
diff --git a/content/renderer/media/DEPS b/content/renderer/media/DEPS
index 3dfd058..0efadbcf 100644
--- a/content/renderer/media/DEPS
+++ b/content/renderer/media/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/viz/common/resources",
   "+third_party/libyuv",
   '+third_party/webrtc_overrides',
 ]
diff --git a/content/renderer/media/android/media_player_renderer_client.cc b/content/renderer/media/android/media_player_renderer_client.cc
index 43cfa0d..f45b5c0 100644
--- a/content/renderer/media/android/media_player_renderer_client.cc
+++ b/content/renderer/media/android/media_player_renderer_client.cc
@@ -138,6 +138,15 @@
   client_->OnWaitingForDecryptionKey();
 }
 
+void MediaPlayerRendererClient::OnAudioConfigChange(
+    const media::AudioDecoderConfig& config) {
+  client_->OnAudioConfigChange(config);
+}
+void MediaPlayerRendererClient::OnVideoConfigChange(
+    const media::VideoDecoderConfig& config) {
+  client_->OnVideoConfigChange(config);
+}
+
 void MediaPlayerRendererClient::OnVideoNaturalSizeChange(
     const gfx::Size& size) {
   stream_texture_wrapper_->UpdateTextureSize(size);
diff --git a/content/renderer/media/android/media_player_renderer_client.h b/content/renderer/media/android/media_player_renderer_client.h
index aad65ef..0ae1a48 100644
--- a/content/renderer/media/android/media_player_renderer_client.h
+++ b/content/renderer/media/android/media_player_renderer_client.h
@@ -63,6 +63,8 @@
   void OnStatisticsUpdate(const media::PipelineStatistics& stats) override;
   void OnBufferingStateChange(media::BufferingState state) override;
   void OnWaitingForDecryptionKey() override;
+  void OnAudioConfigChange(const media::AudioDecoderConfig& config) override;
+  void OnVideoConfigChange(const media::VideoDecoderConfig& config) override;
   void OnVideoNaturalSizeChange(const gfx::Size& size) override;
   void OnVideoOpacityChange(bool opaque) override;
   void OnDurationChange(base::TimeDelta duration) override;
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
index 4d2c678..a3c4fa0 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/unguessable_token.h"
 #include "cc/output/context_provider.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/child/child_thread_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -51,7 +52,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<ui::ContextProviderCommandBuffer>& context_provider,
     bool enable_gpu_memory_buffer_video_frames,
-    const cc::BufferToTextureTargetMap& image_texture_targets,
+    const viz::BufferToTextureTargetMap& image_texture_targets,
     bool enable_video_accelerator) {
   RecordContextProviderPhaseUmaEnum(
       ContextProviderPhase::CONTEXT_PROVIDER_ACQUIRED);
@@ -67,7 +68,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<ui::ContextProviderCommandBuffer>& context_provider,
     bool enable_gpu_memory_buffer_video_frames,
-    const cc::BufferToTextureTargetMap& image_texture_targets,
+    const viz::BufferToTextureTargetMap& image_texture_targets,
     bool enable_video_accelerator)
     : main_thread_task_runner_(main_thread_task_runner),
       task_runner_(task_runner),
@@ -262,7 +263,7 @@
 
 unsigned GpuVideoAcceleratorFactoriesImpl::ImageTextureTarget(
     gfx::BufferFormat format) {
-  auto found = image_texture_targets_.find(cc::BufferToTextureTargetKey(
+  auto found = image_texture_targets_.find(viz::BufferToTextureTargetKey(
       gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, format));
   DCHECK(found != image_texture_targets_.end());
   return found->second;
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
index 969b73f..c8fad256 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
@@ -17,7 +17,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/unguessable_token.h"
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/common/content_export.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
@@ -54,7 +54,7 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<ui::ContextProviderCommandBuffer>& context_provider,
       bool enable_gpu_memory_buffer_video_frames,
-      const cc::BufferToTextureTargetMap& image_texture_targets,
+      const viz::BufferToTextureTargetMap& image_texture_targets,
       bool enable_video_accelerator);
 
   // media::GpuVideoAcceleratorFactories implementation.
@@ -109,7 +109,7 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<ui::ContextProviderCommandBuffer>& context_provider,
       bool enable_gpu_memory_buffer_video_frames,
-      const cc::BufferToTextureTargetMap& image_texture_targets,
+      const viz::BufferToTextureTargetMap& image_texture_targets,
       bool enable_video_accelerator);
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
@@ -127,7 +127,7 @@
 
   // Whether gpu memory buffers should be used to hold video frames data.
   bool enable_gpu_memory_buffer_video_frames_;
-  const cc::BufferToTextureTargetMap image_texture_targets_;
+  const viz::BufferToTextureTargetMap image_texture_targets_;
   // Whether video acceleration encoding/decoding should be enabled.
   const bool video_accelerator_enabled_;
 
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 839ea34..156cc3e 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -205,6 +205,14 @@
           media::kBackgroundVideoTrackOptimization,
           "max_keyframe_distance_media_source_ms",
           base::TimeDelta::FromSeconds(10).InMilliseconds()));
+  // When memory pressure based garbage collection is enabled for MSE, the
+  // |enable_instant_source_buffer_gc| flag controls whether the GC is done
+  // immediately on memory pressure notification or during the next SourceBuffer
+  // append (slower, but is MSE-spec compliant).
+  bool enable_instant_source_buffer_gc =
+      base::GetFieldTrialParamByFeatureAsBool(
+          media::kMemoryPressureBasedSourceBufferGC,
+          "enable_instant_source_buffer_gc", false);
 
   // This must be created for every new WebMediaPlayer, each instance generates
   // a new player id which is used to collate logs on the browser side.
@@ -239,7 +247,7 @@
           initial_cdm, media_surface_manager_, request_routing_token_cb_,
           media_observer, max_keyframe_distance_to_disable_background_video,
           max_keyframe_distance_to_disable_background_video_mse,
-          webkit_preferences.enable_instant_source_buffer_gc,
+          enable_instant_source_buffer_gc,
           GetContentClient()->renderer()->AllowMediaSuspend(),
           embedded_media_experience_enabled));
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index d0dc5c7c..7e70eafe 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4947,20 +4947,7 @@
     params.contents_mime_type = ds->GetResponse().MimeType().Utf8();
 
     params.transition = navigation_state->GetTransitionType();
-    if (!ui::PageTransitionIsMainFrame(params.transition)) {
-      // If the main frame does a load, it should not be reported as a subframe
-      // navigation.  This can occur in the following case:
-      // 1. You're on a site with frames.
-      // 2. You do a subframe navigation.  This is stored with transition type
-      //    MANUAL_SUBFRAME.
-      // 3. You navigate to some non-frame site, say, google.com.
-      // 4. You navigate back to the page from step 2.  Since it was initially
-      //    MANUAL_SUBFRAME, it will be that same transition type here.
-      // We don't want that, because any navigation that changes the toplevel
-      // frame should be tracked as a toplevel navigation (this allows us to
-      // update the URL bar, etc).
-      params.transition = ui::PAGE_TRANSITION_LINK;
-    }
+    DCHECK(ui::PageTransitionIsMainFrame(params.transition));
 
     // If the page contained a client redirect (meta refresh, document.loc...),
     // set the transition appropriately.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 97d5731f..ec0cca1 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -45,7 +45,6 @@
 #include "cc/base/histograms.h"
 #include "cc/base/switches.h"
 #include "cc/blink/web_layer_impl.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/layer_tree_frame_sink.h"
 #include "cc/output/vulkan_in_process_context_provider.h"
@@ -58,6 +57,7 @@
 #include "components/viz/client/client_layer_tree_frame_sink.h"
 #include "components/viz/client/client_shared_bitmap_manager.h"
 #include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/child/appcache/appcache_dispatcher.h"
 #include "content/child/appcache/appcache_frontend_impl.h"
 #include "content/child/blob_storage/blob_message_filter.h"
@@ -825,7 +825,7 @@
   std::string image_texture_target_string =
       command_line.GetSwitchValueASCII(switches::kContentImageTextureTarget);
   buffer_to_texture_target_map_ =
-      cc::StringToBufferToTextureTargetMap(image_texture_target_string);
+      viz::StringToBufferToTextureTargetMap(image_texture_target_string);
 
   if (command_line.HasSwitch(switches::kDisableLCDText)) {
     is_lcd_text_enabled_ = false;
@@ -1605,7 +1605,7 @@
   return is_elastic_overscroll_enabled_;
 }
 
-const cc::BufferToTextureTargetMap&
+const viz::BufferToTextureTargetMap&
 RenderThreadImpl::GetBufferToTextureTargetMap() {
   return buffer_to_texture_target_map_;
 }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 032c899..db02441 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -248,7 +248,7 @@
   bool IsPartialRasterEnabled() override;
   bool IsGpuMemoryBufferCompositorResourcesEnabled() override;
   bool IsElasticOverscrollEnabled() override;
-  const cc::BufferToTextureTargetMap& GetBufferToTextureTargetMap() override;
+  const viz::BufferToTextureTargetMap& GetBufferToTextureTargetMap() override;
   scoped_refptr<base::SingleThreadTaskRunner>
   GetCompositorMainThreadTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner>
@@ -750,7 +750,7 @@
   bool is_gpu_memory_buffer_compositor_resources_enabled_;
   bool is_partial_raster_enabled_;
   bool is_elastic_overscroll_enabled_;
-  cc::BufferToTextureTargetMap buffer_to_texture_target_map_;
+  viz::BufferToTextureTargetMap buffer_to_texture_target_map_;
   bool is_threaded_animation_enabled_;
   bool is_scroll_animator_enabled_;
 
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 417613b0..554ece1 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -20,7 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/app/mojo/mojo_init.h"
 #include "content/common/in_process_child_thread_params.h"
 #include "content/common/resource_messages.h"
@@ -215,8 +215,8 @@
     cmd->AppendSwitchASCII(switches::kNumRasterThreads, "1");
     cmd->AppendSwitchASCII(
         switches::kContentImageTextureTarget,
-        cc::BufferToTextureTargetMapToString(
-            cc::DefaultBufferToTextureTargetMapForTesting()));
+        viz::BufferToTextureTargetMapToString(
+            viz::DefaultBufferToTextureTargetMapForTesting()));
 
     std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler =
         blink::scheduler::RendererScheduler::Create();
diff --git a/content/renderer/renderer_v2.sb b/content/renderer/renderer_v2.sb
index 4e10b34..94745d8 100644
--- a/content/renderer/renderer_v2.sb
+++ b/content/renderer/renderer_v2.sb
@@ -15,18 +15,22 @@
 (define disable-sandbox-denial-logging "DISABLE_SANDBOX_DENIAL_LOGGING")
 (define enable-logging "ENABLE_LOGGING")
 (define homedir-as-literal "USER_HOMEDIR_AS_LITERAL")
-(define elcap-or-later "ELCAP_OR_LATER")
-(define is-mavericks "IS_MAVERICKS")
 (define bundle-path "BUNDLE_PATH")
 (define executable-path "EXECUTABLE_PATH")
 (define chromium-pid "CHROMIUM_PID")
 (define log-file-path "LOG_FILE_PATH")
 (define bundle-id "BUNDLE_ID")
 (define component-path "COMPONENT_PATH")
+(define os-version (string->number (param "OS_VERSION")))
+
+; OS Version numbers
+(define mavericks 1009)
 
 ; Backwards compatibility for 10.9
-(define (path x) (literal x))
-(define (iokit-registry-entry-class x) (iokit-user-client-class x))
+(if (not (defined? 'path))
+  (define path literal))
+(if (not (defined? 'iokit-registry-entry-class))
+  (define iokit-registry-entry-class iokit-user-client-class))
 
 ; --enable-sandbox-logging causes the sandbox to log failures to the syslog.
 (if (param-true? disable-sandbox-denial-logging)
@@ -126,11 +130,11 @@
   (global-name "com.apple.windowserver.active"))
 
 ; MacOS dropped FontServer to replace it with the (XPC based) com.apple.fonts.
-(if (param-true? is-mavericks)
+(if (= os-version mavericks)
   (allow mach-lookup (global-name "com.apple.FontServer")))
 
 ; sysctl
-(if (param-true? is-mavericks)
+(if (= os-version mavericks)
   (allow sysctl-read)
   ; else
   (allow sysctl-read
diff --git a/content/test/DEPS b/content/test/DEPS
index 74d9797..a183ec4 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -5,6 +5,7 @@
   "+components/network_session_configurator/common",
   "+components/scheduler/renderer",
   "+components/scheduler/test",
+  "+components/viz/common/resources",
 
   "+cc/blink",
   "+chromeos/audio", # For WebRTC tests.
diff --git a/content/test/data/accessibility/event/menulist-collapse-expected-win.txt b/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
index 5ed2eb42..2b58648 100644
--- a/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
+++ b/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
@@ -1,2 +1,2 @@
-EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_LISTITEM name="Apple" FOCUSED,INVISIBLE,FOCUSABLE,SELECTABLE
+EVENT_OBJECT_STATECHANGE on role=ROLE_SYSTEM_MENUITEM name="Apple" FOCUSED,INVISIBLE,FOCUSABLE,SELECTABLE
 EVENT_OBJECT_VALUECHANGE on role=ROLE_SYSTEM_COMBOBOX COLLAPSED,FOCUSABLE,HASPOPUP
diff --git a/content/test/data/accessibility/event/menulist-focus-expected-win.txt b/content/test/data/accessibility/event/menulist-focus-expected-win.txt
index ac94789..5e7cc2d 100644
--- a/content/test/data/accessibility/event/menulist-focus-expected-win.txt
+++ b/content/test/data/accessibility/event/menulist-focus-expected-win.txt
@@ -1 +1 @@
-EVENT_OBJECT_FOCUS on role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE
+EVENT_OBJECT_FOCUS on role=ROLE_SYSTEM_MENUITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index 4b26ecc..4187c49d 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -56,7 +56,7 @@
   return true;
 }
 
-const cc::BufferToTextureTargetMap&
+const viz::BufferToTextureTargetMap&
 FakeCompositorDependencies::GetBufferToTextureTargetMap() {
   return buffer_to_texture_target_map_;
 }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h
index d3b5610..23483de 100644
--- a/content/test/fake_compositor_dependencies.h
+++ b/content/test/fake_compositor_dependencies.h
@@ -7,8 +7,8 @@
 
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
-#include "cc/output/buffer_to_texture_target_map.h"
 #include "cc/test/test_task_graph_runner.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/renderer/gpu/compositor_dependencies.h"
 #include "third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h"
 
@@ -29,7 +29,7 @@
   bool IsPartialRasterEnabled() override;
   bool IsGpuMemoryBufferCompositorResourcesEnabled() override;
   bool IsElasticOverscrollEnabled() override;
-  const cc::BufferToTextureTargetMap& GetBufferToTextureTargetMap() override;
+  const viz::BufferToTextureTargetMap& GetBufferToTextureTargetMap() override;
   scoped_refptr<base::SingleThreadTaskRunner>
   GetCompositorMainThreadTaskRunner() override;
   scoped_refptr<base::SingleThreadTaskRunner>
@@ -42,7 +42,7 @@
  private:
   cc::TestTaskGraphRunner task_graph_runner_;
   blink::scheduler::FakeRendererScheduler renderer_scheduler_;
-  cc::BufferToTextureTargetMap buffer_to_texture_target_map_;
+  viz::BufferToTextureTargetMap buffer_to_texture_target_map_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeCompositorDependencies);
 };
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index c9d4204..5d0528a 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -65,3 +65,7 @@
               ['mac', 'linux', 'win', 'android'], bug=735228)
     self.Flaky('Pixel_OffscreenCanvasTransferAfterStyleResize',
               ['mac', 'linux', 'win', 'android'], bug=735171)
+
+    # TODO(junov): update reference images
+    self.Fail('Pixel_CSSFilterEffects', ['mac'], bug=721727)
+    self.Fail('Pixel_CSSFilterEffects_NoOverlays', ['mac'], bug=721727)
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index a90ffa89..55f60f8 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -206,22 +206,8 @@
     self.Flaky('deqp/*', ['win', 'intel', 'd3d11'], bug=628395)
 
     # Passthrough command decoder / D3D11
-    self.Fail('conformance2/glsl3/no-attribute-vertex-shader.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('conformance2/rendering/clearbuffer-sub-source.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-
-    self.Fail('conformance2/textures/image_bitmap_from_canvas/' +
-        'tex-2d-srgb8-rgb-unsigned_byte.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('conformance2/textures/image_bitmap_from_canvas/' +
-        'tex-2d-srgb8_alpha8-rgba-unsigned_byte.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-
     self.Fail('conformance/glsl/misc/shaders-with-name-conflicts.html',
         ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('conformance2/reading/read-pixels-from-fbo-test.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
     self.Skip('conformance2/textures/misc/' +
         'copy-texture-image-webgl-specific.html',
         ['win', 'passthrough', 'd3d11'], bug=602688)
@@ -230,33 +216,11 @@
     self.Skip('conformance2/reading/read-pixels-into-pixel-pack-buffer.html',
         ['win', 'passthrough', 'd3d11'], bug=602688)
 
-    self.Fail('conformance2/reading/format-r11f-g11f-b10f.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-
-    self.Fail('conformance/misc/uninitialized-test.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-
     self.Fail('conformance/reading/read-pixels-test.html',
         ['win', 'passthrough', 'd3d11'], bug=602688)
     self.Fail('conformance/textures/misc/copy-tex-image-and-sub-image-2d.html',
         ['win', 'passthrough', 'd3d11'], bug=602688)
 
-    self.Fail('deqp/functional/gles3/fbocolorbuffer/clear.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/fboinvalidate/sub.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/shaderbuiltinvar.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/framebufferblit/' +
-        'default_framebuffer_*.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/instancedrendering.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/readpixel.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-    self.Fail('deqp/functional/gles3/shaderstruct.html',
-        ['win', 'passthrough', 'd3d11'], bug=602688)
-
     # Mac only.
     self.Fail('conformance2/renderbuffers/' +
         'multisampled-depth-renderbuffer-initialization.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 951ceb0..d9720f8c 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -116,10 +116,6 @@
         ['passthrough'], bug=1523) # angle bug ID
     self.Fail('conformance/glsl/misc/shaders-with-name-conflicts.html',
         ['passthrough'], bug=1639) # angle bug ID
-    self.Fail('conformance/misc/uninitialized-test.html',
-        ['passthrough'], bug=1635) # angle bug ID
-    self.Fail('conformance/reading/read-pixels-test.html',
-        ['passthrough'], bug=1639) # angle bug ID
 
     # Passthrough command decoder / OpenGL
     self.Fail('conformance/buffers/buffer-uninitialized.html',
@@ -127,6 +123,8 @@
     self.Fail('conformance/extensions/' +
         'webgl-draw-buffers-framebuffer-unsupported.html',
         ['passthrough', 'opengl'], bug=682745)
+    self.Fail('conformance/misc/uninitialized-test.html',
+        ['passthrough', 'opengl'], bug=1635) # angle bug ID
     self.Fail('conformance/glsl/misc/shader-with-non-reserved-words.html',
         ['passthrough', 'opengl'], bug=665521)
     self.Fail('conformance/renderbuffers/framebuffer-test.html',
@@ -187,20 +185,8 @@
         ['passthrough', 'opengl', 'amd'], bug=665521)
 
     # Passthrough command decoder / D3D11
-    self.Fail('conformance/glsl/misc/shaders-with-uniform-structs.html',
-        ['passthrough', 'd3d11'], bug=1639) # angle bug ID
     self.Fail('conformance/textures/misc/copy-tex-image-and-sub-image-2d.html',
         ['passthrough', 'd3d11'], bug=1639) # angle bug ID
-    self.Fail('conformance/textures/canvas/' +
-        'tex-2d-rgb-rgb-unsigned_short_5_6_5.html',
-        ['passthrough', 'd3d11'], bug=1635) # angle bug ID
-    self.Fail('conformance/textures/canvas/' +
-        'tex-2d-rgb-rgb-unsigned_byte.html',
-        ['passthrough', 'd3d11'], bug=1635) # angle bug ID
-    self.Fail('conformance/textures/misc/gl-teximage.html',
-        ['passthrough', 'd3d11'], bug=1635) # angle bug ID
-    self.Fail('conformance/textures/misc/texture-mips.html',
-        ['passthrough', 'd3d11'], bug=1635) # angle bug ID
 
     # Win / AMD / Passthrough command decoder / D3D11
     self.Flaky('conformance/textures/misc/copytexsubimage2d-subrects.html',
@@ -211,8 +197,6 @@
         ['win', 'nvidia', 'passthrough', 'd3d11'], bug=737016)
 
     # Win failures
-    self.Fail('conformance/glsl/bugs/angle-ambiguous-function-call.html',
-              bug=731324)
     # Note that the following test seems to pass, but it may still be flaky.
     self.Fail('conformance/glsl/constructors/' +
               'glsl-construct-vec-mat-index.html',
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index f02859d..c73ab4e2 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -69,9 +69,13 @@
 // static
 BluetoothUUID BluetoothAdapterMac::BluetoothUUIDWithCBUUID(CBUUID* uuid) {
   // UUIDString only available OS X >= 10.10.
-  DCHECK(base::mac::IsAtLeastOS10_10());
-  std::string uuid_c_string = base::SysNSStringToUTF8([uuid UUIDString]);
-  return device::BluetoothUUID(uuid_c_string);
+  if (@available(macOS 10.10, *)) {
+    std::string uuid_c_string = base::SysNSStringToUTF8([uuid UUIDString]);
+    return device::BluetoothUUID(uuid_c_string);
+  } else {
+    DCHECK(false);
+    return {};
+  }
 }
 
 // static
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn
index 51b1284..c4fa807 100644
--- a/device/geolocation/BUILD.gn
+++ b/device/geolocation/BUILD.gn
@@ -18,16 +18,16 @@
     "android/geolocation_jni_registrar.h",
     "empty_wifi_data_provider.cc",
     "empty_wifi_data_provider.h",
+    "geolocation_context.cc",
+    "geolocation_context.h",
     "geolocation_delegate.cc",
     "geolocation_delegate.h",
     "geolocation_export.h",
+    "geolocation_impl.cc",
+    "geolocation_impl.h",
     "geolocation_provider.h",
     "geolocation_provider_impl.cc",
     "geolocation_provider_impl.h",
-    "geolocation_service_context.cc",
-    "geolocation_service_context.h",
-    "geolocation_service_impl.cc",
-    "geolocation_service_impl.h",
     "geoposition.cc",
     "geoposition.h",
     "location_api_adapter_android.cc",
diff --git a/device/geolocation/geolocation_context.cc b/device/geolocation/geolocation_context.cc
new file mode 100644
index 0000000..cdfff87a
--- /dev/null
+++ b/device/geolocation/geolocation_context.cc
@@ -0,0 +1,51 @@
+// 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 "device/geolocation/geolocation_context.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "device/geolocation/geolocation_impl.h"
+
+namespace device {
+
+GeolocationContext::GeolocationContext() {}
+
+GeolocationContext::~GeolocationContext() {}
+
+void GeolocationContext::Bind(
+    const service_manager::BindSourceInfo& source_info,
+    mojom::GeolocationRequest request) {
+  GeolocationImpl* impl = new GeolocationImpl(std::move(request), this);
+  impls_.push_back(base::WrapUnique<GeolocationImpl>(impl));
+  if (geoposition_override_)
+    impl->SetOverride(*geoposition_override_.get());
+  else
+    impl->StartListeningForUpdates();
+}
+
+void GeolocationContext::OnConnectionError(GeolocationImpl* impl) {
+  auto it = std::find_if(impls_.begin(), impls_.end(),
+                         [impl](const std::unique_ptr<GeolocationImpl>& gi) {
+                           return impl == gi.get();
+                         });
+  DCHECK(it != impls_.end());
+  impls_.erase(it);
+}
+
+void GeolocationContext::SetOverride(std::unique_ptr<Geoposition> geoposition) {
+  geoposition_override_.swap(geoposition);
+  for (auto& impl : impls_) {
+    impl->SetOverride(*geoposition_override_.get());
+  }
+}
+
+void GeolocationContext::ClearOverride() {
+  for (auto& impl : impls_) {
+    impl->ClearOverride();
+  }
+}
+
+}  // namespace device
diff --git a/device/geolocation/geolocation_context.h b/device/geolocation/geolocation_context.h
new file mode 100644
index 0000000..80b6613
--- /dev/null
+++ b/device/geolocation/geolocation_context.h
@@ -0,0 +1,57 @@
+// 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 DEVICE_GEOLOCATION_GEOLOCATION_CONTEXT_H_
+#define DEVICE_GEOLOCATION_GEOLOCATION_CONTEXT_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "device/geolocation/geolocation_export.h"
+#include "device/geolocation/public/interfaces/geolocation.mojom.h"
+
+namespace service_manager {
+struct BindSourceInfo;
+}
+
+namespace device {
+
+class GeolocationImpl;
+struct Geoposition;
+
+// Provides information to a set of GeolocationImpl instances that are
+// associated with a given context. Notably, allows pausing and resuming
+// geolocation on these instances.
+class DEVICE_GEOLOCATION_EXPORT GeolocationContext {
+ public:
+  GeolocationContext();
+  virtual ~GeolocationContext();
+
+  // Creates a GeolocationImpl that is weakly bound to |request|.
+  void Bind(const service_manager::BindSourceInfo& source_info,
+            mojom::GeolocationRequest request);
+
+  // Called when a GeolocationImpl has a connection error. After this call, it
+  // is no longer safe to access |impl|.
+  void OnConnectionError(GeolocationImpl* impl);
+
+  // Enables geolocation override. This method can be used to trigger possible
+  // location-specific behavior in a particular context.
+  void SetOverride(std::unique_ptr<Geoposition> geoposition);
+
+  // Disables geolocation override.
+  void ClearOverride();
+
+ private:
+  std::vector<std::unique_ptr<GeolocationImpl>> impls_;
+
+  std::unique_ptr<Geoposition> geoposition_override_;
+
+  DISALLOW_COPY_AND_ASSIGN(GeolocationContext);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_GEOLOCATION_GEOLOCATION_CONTEXT_H_
diff --git a/device/geolocation/geolocation_service_impl.cc b/device/geolocation/geolocation_impl.cc
similarity index 79%
rename from device/geolocation/geolocation_service_impl.cc
rename to device/geolocation/geolocation_impl.cc
index ebc145d..16e376a 100644
--- a/device/geolocation/geolocation_service_impl.cc
+++ b/device/geolocation/geolocation_impl.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/geolocation/geolocation_service_impl.h"
+#include "device/geolocation/geolocation_impl.h"
 
 #include <utility>
 
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
-#include "device/geolocation/geolocation_service_context.h"
+#include "device/geolocation/geolocation_context.h"
 
 namespace device {
 
@@ -58,19 +58,18 @@
 
 }  // namespace
 
-GeolocationServiceImpl::GeolocationServiceImpl(
-    mojo::InterfaceRequest<GeolocationService> request,
-    GeolocationServiceContext* context)
+GeolocationImpl::GeolocationImpl(mojo::InterfaceRequest<Geolocation> request,
+                                 GeolocationContext* context)
     : binding_(this, std::move(request)),
       context_(context),
       high_accuracy_(false),
       has_position_to_report_(false) {
   DCHECK(context_);
-  binding_.set_connection_error_handler(base::Bind(
-      &GeolocationServiceImpl::OnConnectionError, base::Unretained(this)));
+  binding_.set_connection_error_handler(
+      base::Bind(&GeolocationImpl::OnConnectionError, base::Unretained(this)));
 }
 
-GeolocationServiceImpl::~GeolocationServiceImpl() {
+GeolocationImpl::~GeolocationImpl() {
   // Make sure to respond to any pending callback even without a valid position.
   if (!position_callback_.is_null()) {
     if (!current_position_.valid) {
@@ -82,11 +81,11 @@
   }
 }
 
-void GeolocationServiceImpl::PauseUpdates() {
+void GeolocationImpl::PauseUpdates() {
   geolocation_subscription_.reset();
 }
 
-void GeolocationServiceImpl::ResumeUpdates() {
+void GeolocationImpl::ResumeUpdates() {
   if (position_override_.Validate()) {
     OnLocationUpdate(position_override_);
     return;
@@ -95,15 +94,15 @@
   StartListeningForUpdates();
 }
 
-void GeolocationServiceImpl::StartListeningForUpdates() {
+void GeolocationImpl::StartListeningForUpdates() {
   geolocation_subscription_ =
       GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
-          base::Bind(&GeolocationServiceImpl::OnLocationUpdate,
+          base::Bind(&GeolocationImpl::OnLocationUpdate,
                      base::Unretained(this)),
           high_accuracy_);
 }
 
-void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) {
+void GeolocationImpl::SetHighAccuracy(bool high_accuracy) {
   UMA_HISTOGRAM_BOOLEAN(
       "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
       high_accuracy);
@@ -117,8 +116,7 @@
   StartListeningForUpdates();
 }
 
-void GeolocationServiceImpl::QueryNextPosition(
-    QueryNextPositionCallback callback) {
+void GeolocationImpl::QueryNextPosition(QueryNextPositionCallback callback) {
   if (!position_callback_.is_null()) {
     DVLOG(1) << "Overlapped call to QueryNextPosition!";
     OnConnectionError();  // Simulate a connection error.
@@ -131,7 +129,7 @@
     ReportCurrentPosition();
 }
 
-void GeolocationServiceImpl::SetOverride(const Geoposition& position) {
+void GeolocationImpl::SetOverride(const Geoposition& position) {
   position_override_ = position;
   if (!position_override_.Validate()) {
     ResumeUpdates();
@@ -142,19 +140,19 @@
   OnLocationUpdate(position_override_);
 }
 
-void GeolocationServiceImpl::ClearOverride() {
+void GeolocationImpl::ClearOverride() {
   position_override_ = Geoposition();
   StartListeningForUpdates();
 }
 
-void GeolocationServiceImpl::OnConnectionError() {
-  context_->ServiceHadConnectionError(this);
+void GeolocationImpl::OnConnectionError() {
+  context_->OnConnectionError(this);
 
   // The above call deleted this instance, so the only safe thing to do is
   // return.
 }
 
-void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
+void GeolocationImpl::OnLocationUpdate(const Geoposition& position) {
   RecordGeopositionErrorCode(position.error_code);
   DCHECK(context_);
 
@@ -177,7 +175,7 @@
     ReportCurrentPosition();
 }
 
-void GeolocationServiceImpl::ReportCurrentPosition() {
+void GeolocationImpl::ReportCurrentPosition() {
   std::move(position_callback_).Run(current_position_.Clone());
   has_position_to_report_ = false;
 }
diff --git a/device/geolocation/geolocation_service_impl.h b/device/geolocation/geolocation_impl.h
similarity index 72%
rename from device/geolocation/geolocation_service_impl.h
rename to device/geolocation/geolocation_impl.h
index a377cce..187393a6 100644
--- a/device/geolocation/geolocation_service_impl.h
+++ b/device/geolocation/geolocation_impl.h
@@ -9,24 +9,23 @@
 #include "device/geolocation/public/interfaces/geolocation.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
-#ifndef DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
-#define DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
+#ifndef DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
+#define DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
 
 namespace device {
 
 class GeolocationProvider;
-class GeolocationServiceContext;
+class GeolocationContext;
 
-// Implements the GeolocationService Mojo interface.
-class GeolocationServiceImpl : public mojom::GeolocationService {
+// Implements the Geolocation Mojo interface.
+class GeolocationImpl : public mojom::Geolocation {
  public:
   // |context| must outlive this object. |update_callback| will be called when
   // location updates are sent, allowing the client to know when the service
   // is being used.
-  GeolocationServiceImpl(
-      mojo::InterfaceRequest<mojom::GeolocationService> request,
-      GeolocationServiceContext* context);
-  ~GeolocationServiceImpl() override;
+  GeolocationImpl(mojo::InterfaceRequest<mojom::Geolocation> request,
+                  GeolocationContext* context);
+  ~GeolocationImpl() override;
 
   // Starts listening for updates.
   void StartListeningForUpdates();
@@ -40,7 +39,7 @@
   void ClearOverride();
 
  private:
-  // mojom::GeolocationService:
+  // mojom::Geolocation:
   void SetHighAccuracy(bool high_accuracy) override;
   void QueryNextPosition(QueryNextPositionCallback callback) override;
 
@@ -50,10 +49,10 @@
   void ReportCurrentPosition();
 
   // The binding between this object and the other end of the pipe.
-  mojo::Binding<mojom::GeolocationService> binding_;
+  mojo::Binding<mojom::Geolocation> binding_;
 
   // Owns this object.
-  GeolocationServiceContext* context_;
+  GeolocationContext* context_;
   std::unique_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
 
   // The callback passed to QueryNextPosition.
@@ -71,9 +70,9 @@
 
   bool has_position_to_report_;
 
-  DISALLOW_COPY_AND_ASSIGN(GeolocationServiceImpl);
+  DISALLOW_COPY_AND_ASSIGN(GeolocationImpl);
 };
 
 }  // namespace device
 
-#endif  // DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
+#endif  // DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
diff --git a/device/geolocation/geolocation_service_context.cc b/device/geolocation/geolocation_service_context.cc
deleted file mode 100644
index c8546a4..0000000
--- a/device/geolocation/geolocation_service_context.cc
+++ /dev/null
@@ -1,55 +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 "device/geolocation/geolocation_service_context.h"
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "device/geolocation/geolocation_service_impl.h"
-
-namespace device {
-
-GeolocationServiceContext::GeolocationServiceContext() {}
-
-GeolocationServiceContext::~GeolocationServiceContext() {}
-
-void GeolocationServiceContext::CreateService(
-    const service_manager::BindSourceInfo& source_info,
-    mojom::GeolocationServiceRequest request) {
-  GeolocationServiceImpl* service =
-      new GeolocationServiceImpl(std::move(request), this);
-  services_.push_back(base::WrapUnique<GeolocationServiceImpl>(service));
-  if (geoposition_override_)
-    service->SetOverride(*geoposition_override_.get());
-  else
-    service->StartListeningForUpdates();
-}
-
-void GeolocationServiceContext::ServiceHadConnectionError(
-    GeolocationServiceImpl* service) {
-  auto it =
-      std::find_if(services_.begin(), services_.end(),
-                   [service](const std::unique_ptr<GeolocationServiceImpl>& s) {
-                     return service == s.get();
-                   });
-  DCHECK(it != services_.end());
-  services_.erase(it);
-}
-
-void GeolocationServiceContext::SetOverride(
-    std::unique_ptr<Geoposition> geoposition) {
-  geoposition_override_.swap(geoposition);
-  for (auto& service : services_) {
-    service->SetOverride(*geoposition_override_.get());
-  }
-}
-
-void GeolocationServiceContext::ClearOverride() {
-  for (auto& service : services_) {
-    service->ClearOverride();
-  }
-}
-
-}  // namespace device
diff --git a/device/geolocation/geolocation_service_context.h b/device/geolocation/geolocation_service_context.h
deleted file mode 100644
index 581fd99..0000000
--- a/device/geolocation/geolocation_service_context.h
+++ /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.
-
-#ifndef DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
-#define DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "device/geolocation/geolocation_export.h"
-#include "device/geolocation/public/interfaces/geolocation.mojom.h"
-
-namespace service_manager {
-struct BindSourceInfo;
-}
-
-namespace device {
-
-class GeolocationServiceImpl;
-struct Geoposition;
-
-// Provides information to a set of GeolocationServiceImpl instances that are
-// associated with a given context. Notably, allows pausing and resuming
-// geolocation on these instances.
-class DEVICE_GEOLOCATION_EXPORT GeolocationServiceContext {
- public:
-  GeolocationServiceContext();
-  virtual ~GeolocationServiceContext();
-
-  // Creates a GeolocationServiceImpl that is weakly bound to |request|.
-  void CreateService(const service_manager::BindSourceInfo& source_info,
-                     mojom::GeolocationServiceRequest request);
-
-  // Called when a service has a connection error. After this call, it is no
-  // longer safe to access |service|.
-  void ServiceHadConnectionError(GeolocationServiceImpl* service);
-
-  // Enables geolocation override. This method can be used to trigger possible
-  // location-specific behavior in a particular context.
-  void SetOverride(std::unique_ptr<Geoposition> geoposition);
-
-  // Disables geolocation override.
-  void ClearOverride();
-
- private:
-  std::vector<std::unique_ptr<GeolocationServiceImpl>> services_;
-
-  std::unique_ptr<Geoposition> geoposition_override_;
-
-  DISALLOW_COPY_AND_ASSIGN(GeolocationServiceContext);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
diff --git a/device/geolocation/public/interfaces/geolocation.mojom b/device/geolocation/public/interfaces/geolocation.mojom
index a510374..7bbc4bb 100644
--- a/device/geolocation/public/interfaces/geolocation.mojom
+++ b/device/geolocation/public/interfaces/geolocation.mojom
@@ -9,7 +9,7 @@
 // The Geolocation service provides updates on the device's location.  By
 // default, it provides updates with low accuracy, but |SetHighAccuracy()| may
 // be called to change this.
-interface GeolocationService {
+interface Geolocation {
   SetHighAccuracy(bool high_accuracy);
 
   // Position is reported once it changes or immediately (to report the initial
diff --git a/extensions/browser/updater/update_client_config.cc b/extensions/browser/updater/update_client_config.cc
index fd18447b..8c21593c 100644
--- a/extensions/browser/updater/update_client_config.cc
+++ b/extensions/browser/updater/update_client_config.cc
@@ -6,6 +6,8 @@
 
 #include "base/sequenced_task_runner.h"
 #include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "build/build_config.h"
 
 namespace extensions {
 
@@ -13,9 +15,16 @@
 
 scoped_refptr<base::SequencedTaskRunner>
 UpdateClientConfig::GetSequencedTaskRunner() const {
-  return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::BACKGROUND,
-       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  constexpr base::TaskTraits traits = {
+      base::MayBlock(), base::TaskPriority::BACKGROUND,
+      base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
+#if defined(OS_WIN)
+  // Use the COM STA task runner as the Windows background downloader requires
+  // COM initialization.
+  return base::CreateCOMSTATaskRunnerWithTraits(traits);
+#else
+  return base::CreateSequencedTaskRunnerWithTraits(traits);
+#endif
 }
 
 UpdateClientConfig::~UpdateClientConfig() {}
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index c7722c0..1e43a67 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -35,6 +35,8 @@
     "bindings/api_binding_js_util.h",
     "bindings/api_binding_types.cc",
     "bindings/api_binding_types.h",
+    "bindings/api_binding_util.cc",
+    "bindings/api_binding_util.h",
     "bindings/api_bindings_system.cc",
     "bindings/api_bindings_system.h",
     "bindings/api_event_handler.cc",
diff --git a/extensions/renderer/api_activity_logger.cc b/extensions/renderer/api_activity_logger.cc
index baaca3f..71cd1e4a 100644
--- a/extensions/renderer/api_activity_logger.cc
+++ b/extensions/renderer/api_activity_logger.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 "extensions/renderer/api_activity_logger.h"
+
 #include <stddef.h>
 
 #include <string>
@@ -11,8 +13,8 @@
 #include "content/public/renderer/render_thread.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/renderer/activity_log_converter_strategy.h"
-#include "extensions/renderer/api_activity_logger.h"
 #include "extensions/renderer/dispatcher.h"
+#include "extensions/renderer/extensions_renderer_client.h"
 #include "extensions/renderer/script_context.h"
 
 namespace extensions {
@@ -20,28 +22,45 @@
 APIActivityLogger::APIActivityLogger(ScriptContext* context,
                                      Dispatcher* dispatcher)
     : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) {
-  RouteFunction("LogEvent", base::Bind(&APIActivityLogger::LogEvent,
-                                       base::Unretained(this)));
-  RouteFunction("LogAPICall", base::Bind(&APIActivityLogger::LogAPICall,
-                                         base::Unretained(this)));
+  RouteFunction("LogEvent", base::Bind(&APIActivityLogger::LogForJS,
+                                       base::Unretained(this), EVENT));
+  RouteFunction("LogAPICall", base::Bind(&APIActivityLogger::LogForJS,
+                                         base::Unretained(this), APICALL));
 }
 
 APIActivityLogger::~APIActivityLogger() {}
 
 // static
 void APIActivityLogger::LogAPICall(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  LogInternal(APICALL, args);
+    v8::Local<v8::Context> context,
+    const std::string& call_name,
+    const std::vector<v8::Local<v8::Value>>& arguments) {
+  const Dispatcher* dispatcher =
+      ExtensionsRendererClient::Get()->GetDispatcher();
+  if (!dispatcher ||  // dispatcher can be null in unittests.
+      !dispatcher->activity_logging_enabled()) {
+    return;
+  }
+
+  ScriptContext* script_context =
+      ScriptContextSet::GetContextByV8Context(context);
+  auto value_args = base::MakeUnique<base::ListValue>();
+  std::unique_ptr<content::V8ValueConverter> converter =
+      content::V8ValueConverter::Create();
+  ActivityLogConverterStrategy strategy;
+  converter->SetFunctionAllowed(true);
+  converter->SetStrategy(&strategy);
+  value_args->Reserve(arguments.size());
+  // TODO(devlin): This doesn't protect against custom properties, so it might
+  // not perfectly reflect the passed arguments.
+  for (const auto& arg : arguments)
+    value_args->Append(converter->FromV8Value(arg, context));
+
+  LogInternal(APICALL, script_context->GetExtensionID(), call_name,
+              std::move(value_args), std::string());
 }
 
-// static
-void APIActivityLogger::LogEvent(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  LogInternal(EVENT, args);
-}
-
-// static
-void APIActivityLogger::LogInternal(
+void APIActivityLogger::LogForJS(
     const CallType call_type,
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   CHECK_GT(args.Length(), 2);
@@ -52,38 +71,51 @@
   if (!dispatcher_->activity_logging_enabled())
     return;
 
-  std::string ext_id = *v8::String::Utf8Value(args[0]);
-  ExtensionHostMsg_APIActionOrEvent_Params params;
-  params.api_call = *v8::String::Utf8Value(args[1]);
-  if (args.Length() == 4)  // Extras are optional.
-    params.extra = *v8::String::Utf8Value(args[3]);
-  else
-    params.extra = "";
+  v8::Isolate* isolate = args.GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context = isolate->GetCurrentContext();
 
-  // Get the array of api call arguments.
+  std::string extension_id = *v8::String::Utf8Value(args[0]);
+  std::string call_name = *v8::String::Utf8Value(args[1]);
+  std::string extra;
+  if (args.Length() == 4) {  // Extras are optional.
+    CHECK(args[3]->IsString());
+    extra = *v8::String::Utf8Value(args[3]);
+  }
+
+  // Get the array of call arguments.
+  auto arguments = base::MakeUnique<base::ListValue>();
   v8::Local<v8::Array> arg_array = v8::Local<v8::Array>::Cast(args[2]);
   if (arg_array->Length() > 0) {
+    arguments->Reserve(arg_array->Length());
     std::unique_ptr<content::V8ValueConverter> converter =
         content::V8ValueConverter::Create();
     ActivityLogConverterStrategy strategy;
     converter->SetFunctionAllowed(true);
     converter->SetStrategy(&strategy);
-    std::unique_ptr<base::ListValue> arg_list(new base::ListValue());
-    for (size_t i = 0; i < arg_array->Length(); ++i) {
-      arg_list->Set(
-          i,
-          converter->FromV8Value(arg_array->Get(i),
-                                 args.GetIsolate()->GetCurrentContext()));
-    }
-    params.arguments.Swap(arg_list.get());
+    for (size_t i = 0; i < arg_array->Length(); ++i)
+      arguments->Append(converter->FromV8Value(arg_array->Get(i), context));
   }
 
+  LogInternal(call_type, extension_id, call_name, std::move(arguments), extra);
+}
+
+// static
+void APIActivityLogger::LogInternal(const CallType call_type,
+                                    const std::string& extension_id,
+                                    const std::string& call_name,
+                                    std::unique_ptr<base::ListValue> arguments,
+                                    const std::string& extra) {
+  ExtensionHostMsg_APIActionOrEvent_Params params;
+  params.api_call = call_name;
+  params.arguments.Swap(arguments.get());
+  params.extra = extra;
   if (call_type == APICALL) {
     content::RenderThread::Get()->Send(
-        new ExtensionHostMsg_AddAPIActionToActivityLog(ext_id, params));
+        new ExtensionHostMsg_AddAPIActionToActivityLog(extension_id, params));
   } else if (call_type == EVENT) {
     content::RenderThread::Get()->Send(
-        new ExtensionHostMsg_AddEventToActivityLog(ext_id, params));
+        new ExtensionHostMsg_AddEventToActivityLog(extension_id, params));
   }
 }
 
diff --git a/extensions/renderer/api_activity_logger.h b/extensions/renderer/api_activity_logger.h
index 08f614a..2f586b53 100644
--- a/extensions/renderer/api_activity_logger.h
+++ b/extensions/renderer/api_activity_logger.h
@@ -5,13 +5,18 @@
 #ifndef EXTENSIONS_RENDERER_API_ACTIVITY_LOGGER_H_
 #define EXTENSIONS_RENDERER_API_ACTIVITY_LOGGER_H_
 
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
-#include "extensions/common/features/feature.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "v8/include/v8.h"
 
+namespace base {
+class ListValue;
+}
+
 namespace extensions {
 class Dispatcher;
 
@@ -23,28 +28,31 @@
   APIActivityLogger(ScriptContext* context, Dispatcher* dispatcher);
   ~APIActivityLogger() override;
 
+  // Notifies the browser that an API method has been called, if and only if
+  // activity logging is enabled.
+  static void LogAPICall(v8::Local<v8::Context> context,
+                         const std::string& call_name,
+                         const std::vector<v8::Local<v8::Value>>& arguments);
+
  private:
   // Used to distinguish API calls & events from each other in LogInternal.
   enum CallType { APICALL, EVENT };
 
   // This is ultimately invoked in bindings.js with JavaScript arguments.
   //    arg0 - extension ID as a string
-  //    arg1 - API call name as a string
-  //    arg2 - arguments to the API call
+  //    arg1 - API method/Event name as a string
+  //    arg2 - arguments to the API call/event
   //    arg3 - any extra logging info as a string (optional)
-  void LogAPICall(const v8::FunctionCallbackInfo<v8::Value>& args);
+  // TODO(devlin): Does arg3 ever exist?
+  void LogForJS(const CallType call_type,
+                const v8::FunctionCallbackInfo<v8::Value>& args);
 
-  // This is ultimately invoked in bindings.js with JavaScript arguments.
-  //    arg0 - extension ID as a string
-  //    arg1 - Event name as a string
-  //    arg2 - Event arguments
-  //    arg3 - any extra logging info as a string (optional)
-  void LogEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // LogAPICall and LogEvent are really the same underneath except for
-  // how they are ultimately dispatched to the log.
-  void LogInternal(const CallType call_type,
-                   const v8::FunctionCallbackInfo<v8::Value>& args);
+  // Common implementation method for sending a logging IPC.
+  static void LogInternal(const CallType call_type,
+                          const std::string& extension_id,
+                          const std::string& call_name,
+                          std::unique_ptr<base::ListValue> arguments,
+                          const std::string& extra);
 
   Dispatcher* dispatcher_;
 
diff --git a/extensions/renderer/bindings/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
index d5ee62f..b1d0169 100644
--- a/extensions/renderer/bindings/api_binding.cc
+++ b/extensions/renderer/bindings/api_binding.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "extensions/renderer/bindings/api_binding_hooks.h"
 #include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/bindings/api_event_handler.h"
 #include "extensions/renderer/bindings/api_invocation_errors.h"
 #include "extensions/renderer/bindings/api_request_handler.h"
@@ -30,21 +31,6 @@
 
 namespace {
 
-std::string GetPlatformString() {
-#if defined(OS_CHROMEOS)
-  return "chromeos";
-#elif defined(OS_LINUX)
-  return "linux";
-#elif defined(OS_MACOSX)
-  return "mac";
-#elif defined(OS_WIN)
-  return "win";
-#else
-  NOTREACHED();
-  return std::string();
-#endif
-}
-
 // Returns the name of the enum value for use in JavaScript; JS enum entries use
 // SCREAMING_STYLE.
 std::string GetJSEnumEntryName(const std::string& original) {
@@ -193,6 +179,7 @@
                        const base::ListValue* event_definitions,
                        const base::DictionaryValue* property_definitions,
                        const CreateCustomType& create_custom_type,
+                       const OnSilentRequest& on_silent_request,
                        std::unique_ptr<APIBindingHooks> binding_hooks,
                        APITypeReferenceMap* type_refs,
                        APIRequestHandler* request_handler,
@@ -201,6 +188,7 @@
     : api_name_(api_name),
       property_definitions_(property_definitions),
       create_custom_type_(create_custom_type),
+      on_silent_request_(on_silent_request),
       binding_hooks_(std::move(binding_hooks)),
       type_refs_(type_refs),
       request_handler_(request_handler),
@@ -452,7 +440,7 @@
     // this check here. If this becomes more common, we should really find a
     // way of moving these checks to the features files.
     if (dict->GetList("platforms", &platforms)) {
-      std::string this_platform = GetPlatformString();
+      std::string this_platform = binding::GetPlatformString();
       auto is_this_platform = [&this_platform](const base::Value& platform) {
         return platform.is_string() && platform.GetString() == this_platform;
       };
@@ -584,6 +572,7 @@
   bool invalid_invocation = false;
   v8::Local<v8::Function> custom_callback;
   bool updated_args = false;
+  int old_request_id = request_handler_->last_sent_request_id();
   {
     v8::TryCatch try_catch(isolate);
     APIBindingHooks::RequestResult hooks_result = binding_hooks_->RunHooks(
@@ -602,6 +591,14 @@
       case APIBindingHooks::RequestResult::HANDLED:
         if (!hooks_result.return_value.IsEmpty())
           arguments->Return(hooks_result.return_value);
+
+        // TODO(devlin): This is a pretty simplistic implementation of this,
+        // but it's similar to the current JS logic. If we wanted to be more
+        // correct, we could create a RequestScope object that watches outgoing
+        // requests.
+        if (old_request_id == request_handler_->last_sent_request_id())
+          on_silent_request_.Run(context, name, argument_list);
+
         return;  // Our work here is done.
       case APIBindingHooks::RequestResult::ARGUMENTS_UPDATED:
         updated_args = true;  // Intentional fall-through.
diff --git a/extensions/renderer/bindings/api_binding.h b/extensions/renderer/bindings/api_binding.h
index 3412e6e2..8f896ec 100644
--- a/extensions/renderer/bindings/api_binding.h
+++ b/extensions/renderer/bindings/api_binding.h
@@ -52,6 +52,12 @@
       const std::string& property_name,
       const base::ListValue* property_values)>;
 
+  // Called when a request is handled without notifying the browser.
+  using OnSilentRequest =
+      base::Callback<void(v8::Local<v8::Context>,
+                          const std::string& name,
+                          const std::vector<v8::Local<v8::Value>>& arguments)>;
+
   // The callback type for handling an API call.
   using HandlerCallback = base::Callback<void(gin::Arguments*)>;
 
@@ -64,6 +70,7 @@
              const base::ListValue* event_definitions,
              const base::DictionaryValue* property_definitions,
              const CreateCustomType& create_custom_type,
+             const OnSilentRequest& on_silent_request,
              std::unique_ptr<APIBindingHooks> binding_hooks,
              APITypeReferenceMap* type_refs,
              APIRequestHandler* request_handler,
@@ -131,6 +138,8 @@
   // The callback for constructing a custom type.
   CreateCustomType create_custom_type_;
 
+  OnSilentRequest on_silent_request_;
+
   // The registered hooks for this API.
   std::unique_ptr<APIBindingHooks> binding_hooks_;
 
diff --git a/extensions/renderer/bindings/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
index 73e1ab3..b8e52c22 100644
--- a/extensions/renderer/bindings/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -20,6 +20,7 @@
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 #include "v8/include/v8.h"
@@ -80,6 +81,11 @@
                              bool was_manual,
                              v8::Local<v8::Context> context) {}
 
+void DoNothingWithSilentRequest(
+    v8::Local<v8::Context> context,
+    const std::string& call_name,
+    const std::vector<v8::Local<v8::Value>>& arguments) {}
+
 }  // namespace
 
 class APIBindingUnittest : public APIBindingTest {
@@ -150,6 +156,10 @@
     create_custom_type_ = callback;
   }
 
+  void SetOnSilentRequest(const APIBinding::OnSilentRequest& callback) {
+    on_silent_request_ = callback;
+  }
+
   void SetAvailabilityCallback(
       const BindingAccessChecker::AvailabilityCallback& callback) {
     availability_callback_ = callback;
@@ -162,6 +172,8 @@
     }
     if (binding_hooks_delegate_)
       binding_hooks_->SetDelegate(std::move(binding_hooks_delegate_));
+    if (!on_silent_request_)
+      on_silent_request_ = base::Bind(&DoNothingWithSilentRequest);
     if (!availability_callback_)
       availability_callback_ = base::Bind(&AllowAllFeatures);
     event_handler_ = base::MakeUnique<APIEventHandler>(
@@ -173,8 +185,8 @@
     binding_ = base::MakeUnique<APIBinding>(
         kBindingName, binding_functions_.get(), binding_types_.get(),
         binding_events_.get(), binding_properties_.get(), create_custom_type_,
-        std::move(binding_hooks_), &type_refs_, request_handler_.get(),
-        event_handler_.get(), access_checker_.get());
+        on_silent_request_, std::move(binding_hooks_), &type_refs_,
+        request_handler_.get(), event_handler_.get(), access_checker_.get());
     EXPECT_EQ(!binding_types_.get(), type_refs_.empty());
   }
 
@@ -243,6 +255,7 @@
   std::unique_ptr<APIBindingHooks> binding_hooks_;
   std::unique_ptr<APIBindingHooksDelegate> binding_hooks_delegate_;
   APIBinding::CreateCustomType create_custom_type_;
+  APIBinding::OnSilentRequest on_silent_request_;
   BindingAccessChecker::AvailabilityCallback availability_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(APIBindingUnittest);
@@ -1301,4 +1314,188 @@
             GetStringPropertyFromObject(binding_object, context, "oneString"));
 }
 
+// Test that running hooks returning different results correctly sends requests
+// or notifies of silent requests.
+TEST_F(APIBindingUnittest, TestSendingRequestsAndSilentRequestsWithHooks) {
+  SetFunctions(
+      "[{"
+      "  'name': 'modifyArgs',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'invalidInvocation',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'throwException',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'dontHandle',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'handle',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'handleAndSendRequest',"
+      "  'parameters': []"
+      "}, {"
+      "  'name': 'handleWithArgs',"
+      "  'parameters': [{"
+      "    'name': 'first',"
+      "    'type': 'string'"
+      "  }, {"
+      "    'name': 'second',"
+      "    'type': 'integer'"
+      "  }]"
+      "}]");
+
+  using RequestResult = APIBindingHooks::RequestResult;
+
+  auto basic_handler = [](RequestResult::ResultCode code, const APISignature*,
+                          v8::Local<v8::Context> context,
+                          std::vector<v8::Local<v8::Value>>* arguments,
+                          const APITypeReferenceMap& map) {
+    return RequestResult(code);
+  };
+
+  auto hooks = base::MakeUnique<APIBindingHooksTestDelegate>();
+  hooks->AddHandler(
+      "test.modifyArgs",
+      base::Bind(basic_handler, RequestResult::ARGUMENTS_UPDATED));
+  hooks->AddHandler(
+      "test.invalidInvocation",
+      base::Bind(basic_handler, RequestResult::INVALID_INVOCATION));
+  hooks->AddHandler("test.dontHandle",
+                    base::Bind(basic_handler, RequestResult::NOT_HANDLED));
+  hooks->AddHandler("test.handle",
+                    base::Bind(basic_handler, RequestResult::HANDLED));
+  hooks->AddHandler(
+      "test.throwException",
+      base::Bind([](const APISignature*, v8::Local<v8::Context> context,
+                    std::vector<v8::Local<v8::Value>>* arguments,
+                    const APITypeReferenceMap& map) {
+        context->GetIsolate()->ThrowException(
+            gin::StringToV8(context->GetIsolate(), "some error"));
+        return RequestResult(RequestResult::THROWN);
+      }));
+  hooks->AddHandler(
+      "test.handleWithArgs",
+      base::Bind([](const APISignature*, v8::Local<v8::Context> context,
+                    std::vector<v8::Local<v8::Value>>* arguments,
+                    const APITypeReferenceMap& map) {
+        arguments->push_back(v8::Integer::New(context->GetIsolate(), 42));
+        return RequestResult(RequestResult::HANDLED);
+      }));
+
+  auto handle_and_send_request =
+      [](APIRequestHandler* handler, const APISignature*,
+         v8::Local<v8::Context> context,
+         std::vector<v8::Local<v8::Value>>* arguments,
+         const APITypeReferenceMap& map) {
+        handler->StartRequest(
+            context, "test.handleAndSendRequest",
+            base::MakeUnique<base::ListValue>(), v8::Local<v8::Function>(),
+            v8::Local<v8::Function>(), binding::RequestThread::UI);
+        return RequestResult(RequestResult::HANDLED);
+      };
+  hooks->AddHandler("test.handleAndSendRequest",
+                    base::Bind(handle_and_send_request, request_handler()));
+
+  SetHooksDelegate(std::move(hooks));
+
+  auto on_silent_request =
+      [](base::Optional<std::string>* name_out,
+         base::Optional<std::vector<std::string>>* args_out,
+         v8::Local<v8::Context> context, const std::string& call_name,
+         const std::vector<v8::Local<v8::Value>>& arguments) {
+        *name_out = call_name;
+        *args_out = std::vector<std::string>();
+        (*args_out)->reserve(arguments.size());
+        for (const auto& arg : arguments)
+          (*args_out)->push_back(V8ToString(arg, context));
+      };
+  base::Optional<std::string> silent_request;
+  base::Optional<std::vector<std::string>> request_arguments;
+  SetOnSilentRequest(
+      base::Bind(on_silent_request, &silent_request, &request_arguments));
+
+  InitializeBinding();
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = MainContext();
+
+  v8::Local<v8::Object> binding_object = binding()->CreateInstance(context);
+
+  auto call_api_method = [binding_object, context](
+                             base::StringPiece name,
+                             base::StringPiece string_args) {
+    v8::Local<v8::Function> call = FunctionFromString(
+        context, base::StringPrintf("(function(binding) { binding.%s(%s); })",
+                                    name.data(), string_args.data()));
+    v8::Local<v8::Value> args[] = {binding_object};
+    v8::TryCatch try_catch(context->GetIsolate());
+    // The throwException call will throw an exception; ignore it.
+    ignore_result(call->Call(context, v8::Undefined(context->GetIsolate()),
+                             arraysize(args), args));
+  };
+
+  call_api_method("modifyArgs", "");
+  ASSERT_TRUE(last_request());
+  EXPECT_EQ("test.modifyArgs", last_request()->method_name);
+  EXPECT_FALSE(silent_request);
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("invalidInvocation", "");
+  EXPECT_FALSE(last_request());
+  EXPECT_FALSE(silent_request);
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("throwException", "");
+  EXPECT_FALSE(last_request());
+  EXPECT_FALSE(silent_request);
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("dontHandle", "");
+  ASSERT_TRUE(last_request());
+  EXPECT_EQ("test.dontHandle", last_request()->method_name);
+  EXPECT_FALSE(silent_request);
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("handle", "");
+  EXPECT_FALSE(last_request());
+  ASSERT_TRUE(silent_request);
+  EXPECT_EQ("test.handle", *silent_request);
+  ASSERT_TRUE(request_arguments);
+  EXPECT_TRUE(request_arguments->empty());
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("handleAndSendRequest", "");
+  ASSERT_TRUE(last_request());
+  EXPECT_EQ("test.handleAndSendRequest", last_request()->method_name);
+  EXPECT_FALSE(silent_request);
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+
+  call_api_method("handleWithArgs", "'str'");
+  EXPECT_FALSE(last_request());
+  ASSERT_TRUE(silent_request);
+  ASSERT_EQ("test.handleWithArgs", *silent_request);
+  ASSERT_TRUE(request_arguments);
+  EXPECT_THAT(
+      *request_arguments,
+      testing::ElementsAre("\"str\"", "42"));  // 42 was added by the handler.
+  reset_last_request();
+  silent_request.reset();
+  request_arguments.reset();
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_util.cc b/extensions/renderer/bindings/api_binding_util.cc
new file mode 100644
index 0000000..2dae6f8
--- /dev/null
+++ b/extensions/renderer/bindings/api_binding_util.cc
@@ -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.
+
+#include "extensions/renderer/bindings/api_binding_util.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace extensions {
+namespace binding {
+
+std::string GetPlatformString() {
+#if defined(OS_CHROMEOS)
+  return "chromeos";
+#elif defined(OS_LINUX)
+  return "linux";
+#elif defined(OS_MACOSX)
+  return "mac";
+#elif defined(OS_WIN)
+  return "win";
+#else
+  NOTREACHED();
+  return std::string();
+#endif
+}
+
+}  // namespace binding
+}  // namespace extensions
diff --git a/extensions/renderer/bindings/api_binding_util.h b/extensions/renderer/bindings/api_binding_util.h
new file mode 100644
index 0000000..10f95a3b
--- /dev/null
+++ b/extensions/renderer/bindings/api_binding_util.h
@@ -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.
+
+#ifndef EXTENSIONS_RENDERER_BINDING_API_BINDING_UTIL_H_
+#define EXTENSIONS_RENDERER_BINDING_API_BINDING_UTIL_H_
+
+#include <string>
+
+namespace extensions {
+namespace binding {
+
+// Returns the string version of the current platform, one of "chromeos",
+// "linux", "win", or "mac".
+std::string GetPlatformString();
+
+}  // namespace binding
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_BINDING_API_BINDING_UTIL_H_
diff --git a/extensions/renderer/bindings/api_bindings_system.cc b/extensions/renderer/bindings/api_bindings_system.cc
index fb456d0..e20e1a0 100644
--- a/extensions/renderer/bindings/api_bindings_system.cc
+++ b/extensions/renderer/bindings/api_bindings_system.cc
@@ -18,6 +18,7 @@
     const BindingAccessChecker::AvailabilityCallback& is_available,
     const APIRequestHandler::SendRequestMethod& send_request,
     const APIEventHandler::EventListenersChangedMethod& event_listeners_changed,
+    const APIBinding::OnSilentRequest& on_silent_request,
     APILastError last_error)
     : type_reference_map_(base::Bind(&APIBindingsSystem::InitializeType,
                                      base::Unretained(this))),
@@ -26,7 +27,8 @@
       access_checker_(is_available),
       call_js_(call_js),
       call_js_sync_(call_js_sync),
-      get_api_schema_(get_api_schema) {}
+      get_api_schema_(get_api_schema),
+      on_silent_request_(on_silent_request) {}
 
 APIBindingsSystem::~APIBindingsSystem() {}
 
@@ -72,8 +74,8 @@
       api_name, function_definitions, type_definitions, event_definitions,
       property_definitions,
       base::Bind(&APIBindingsSystem::CreateCustomType, base::Unretained(this)),
-      std::move(hooks), &type_reference_map_, &request_handler_,
-      &event_handler_, &access_checker_);
+      on_silent_request_, std::move(hooks), &type_reference_map_,
+      &request_handler_, &event_handler_, &access_checker_);
 }
 
 void APIBindingsSystem::InitializeType(const std::string& type_name) {
diff --git a/extensions/renderer/bindings/api_bindings_system.h b/extensions/renderer/bindings/api_bindings_system.h
index 00d205f..82351c3 100644
--- a/extensions/renderer/bindings/api_bindings_system.h
+++ b/extensions/renderer/bindings/api_bindings_system.h
@@ -51,6 +51,7 @@
       const APIRequestHandler::SendRequestMethod& send_request,
       const APIEventHandler::EventListenersChangedMethod&
           event_listeners_changed,
+      const APIBinding::OnSilentRequest& on_silent_request,
       APILastError last_error);
   ~APIBindingsSystem();
 
@@ -141,6 +142,10 @@
   // API. Curried in for testing purposes so we can use fake APIs.
   GetAPISchemaMethod get_api_schema_;
 
+  // The method to call when the system silently handles an API request without
+  // notifying the browser.
+  APIBinding::OnSilentRequest on_silent_request_;
+
   DISALLOW_COPY_AND_ASSIGN(APIBindingsSystem);
 };
 
diff --git a/extensions/renderer/bindings/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
index 6c0eb0a..aea5e56 100644
--- a/extensions/renderer/bindings/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -94,6 +94,11 @@
   return true;
 }
 
+void DoNothingWithSilentRequest(
+    v8::Local<v8::Context> context,
+    const std::string& call_name,
+    const std::vector<v8::Local<v8::Value>>& arguments) {}
+
 }  // namespace
 
 APIBindingsSystemTest::APIBindingsSystemTest() {}
@@ -118,6 +123,7 @@
       base::Bind(&APIBindingsSystemTest::OnAPIRequest, base::Unretained(this)),
       base::Bind(&APIBindingsSystemTest::OnEventListenersChanged,
                  base::Unretained(this)),
+      base::Bind(&DoNothingWithSilentRequest),
       APILastError(base::Bind(&APIBindingsSystemTest::GetLastErrorParent,
                               base::Unretained(this)),
                    APILastError::AddConsoleError()));
diff --git a/extensions/renderer/bindings/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
index e13c9e58..2aa6e29 100644
--- a/extensions/renderer/bindings/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -106,6 +106,7 @@
   request->method_name = method;
   request->thread = thread;
 
+  last_sent_request_id_ = request_id;
   send_request_.Run(std::move(request), context);
   return request_id;
 }
diff --git a/extensions/renderer/bindings/api_request_handler.h b/extensions/renderer/bindings/api_request_handler.h
index c395aa7a..a2ce5da8e 100644
--- a/extensions/renderer/bindings/api_request_handler.h
+++ b/extensions/renderer/bindings/api_request_handler.h
@@ -85,6 +85,7 @@
   void InvalidateContext(v8::Local<v8::Context> context);
 
   APILastError* last_error() { return &last_error_; }
+  int last_sent_request_id() const { return last_sent_request_id_; }
 
   std::set<int> GetPendingRequestIdsForTesting() const;
 
@@ -108,6 +109,11 @@
   // The next available request identifier.
   int next_request_id_ = 0;
 
+  // The id of the last request we sent to the browser. This can be used as a
+  // flag for whether or not a request was sent (if the last_sent_request_id_
+  // changes).
+  int last_sent_request_id_ = -1;
+
   // A map of all pending requests.
   std::map<int, PendingRequest> pending_requests_;
 
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 73b7125..f1808e53 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -13,6 +13,7 @@
 #include "extensions/common/extension_api.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/features/feature_provider.h"
+#include "extensions/renderer/api_activity_logger.h"
 #include "extensions/renderer/bindings/api_binding_bridge.h"
 #include "extensions/renderer/bindings/api_binding_hooks.h"
 #include "extensions/renderer/bindings/api_binding_js_util.h"
@@ -361,6 +362,7 @@
                      base::Unretained(this)),
           base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged,
                      base::Unretained(this)),
+          base::Bind(&APIActivityLogger::LogAPICall),
           APILastError(base::Bind(&GetLastErrorParents),
                        base::Bind(&AddConsoleError))),
       weak_factory_(this) {
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 85dbc1a..8747b54 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -22,6 +22,7 @@
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/script_context_set.h"
 #include "extensions/renderer/string_source_map.h"
+#include "extensions/renderer/test_extensions_renderer_client.h"
 #include "extensions/renderer/test_v8_extension_configuration.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -203,6 +204,7 @@
   std::unique_ptr<MockEventChangeHandler> event_change_handler_;
 
   StringSourceMap source_map_;
+  TestExtensionsRendererClient renderer_client_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeExtensionBindingsSystemUnittest);
 };
diff --git a/extensions/renderer/process_info_native_handler.cc b/extensions/renderer/process_info_native_handler.cc
index 545a212..32a15b8 100644
--- a/extensions/renderer/process_info_native_handler.cc
+++ b/extensions/renderer/process_info_native_handler.cc
@@ -8,7 +8,9 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "extensions/renderer/bindings/api_binding_util.h"
 #include "extensions/renderer/script_context.h"
+#include "gin/converter.h"
 
 namespace extensions {
 
@@ -48,6 +50,9 @@
   RouteFunction(
       "HasSwitch",
       base::Bind(&ProcessInfoNativeHandler::HasSwitch, base::Unretained(this)));
+  RouteFunction("GetPlatform",
+                base::Bind(&ProcessInfoNativeHandler::GetPlatform,
+                           base::Unretained(this)));
 }
 
 void ProcessInfoNativeHandler::GetExtensionId(
@@ -95,4 +100,11 @@
   args.GetReturnValue().Set(v8::Boolean::New(args.GetIsolate(), has_switch));
 }
 
+void ProcessInfoNativeHandler::GetPlatform(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CHECK_EQ(0, args.Length());
+  args.GetReturnValue().Set(
+      gin::StringToSymbol(args.GetIsolate(), binding::GetPlatformString()));
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/process_info_native_handler.h b/extensions/renderer/process_info_native_handler.h
index dcde430..9f8b532 100644
--- a/extensions/renderer/process_info_native_handler.h
+++ b/extensions/renderer/process_info_native_handler.h
@@ -29,6 +29,7 @@
   void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args);
   void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args);
   void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
+  void GetPlatform(const v8::FunctionCallbackInfo<v8::Value>& args);
 
   std::string extension_id_;
   std::string context_type_;
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js
index d0b7e61b..92034552 100644
--- a/extensions/renderer/resources/binding.js
+++ b/extensions/renderer/resources/binding.js
@@ -20,6 +20,7 @@
 var contextType = process.GetContextType();
 var extensionId = process.GetExtensionId();
 var manifestVersion = process.GetManifestVersion();
+var platform = process.GetPlatform();
 var sendRequest = sendRequestHandler.sendRequest;
 
 // Stores the name and definition of each API function, with methods to
@@ -87,24 +88,6 @@
   return this.setHook_(apiName, 'customCallback', customizedFunction);
 };
 
-// Get the platform from navigator.appVersion.
-function getPlatform() {
-  var platforms = [
-    [/CrOS Touch/, "chromeos touch"],
-    [/CrOS/, "chromeos"],
-    [/Linux/, "linux"],
-    [/Mac/, "mac"],
-    [/Win/, "win"],
-  ];
-
-  for (var i = 0; i < platforms.length; i++) {
-    if ($RegExp.exec(platforms[i][0], navigator.appVersion)) {
-      return platforms[i][1];
-    }
-  }
-  return "unknown";
-}
-
 function isPlatformSupported(schemaNode, platform) {
   return !schemaNode.platforms ||
       $Array.indexOf(schemaNode.platforms, platform) > -1;
@@ -145,8 +128,6 @@
   return customType;
 }
 
-var platform = getPlatform();
-
 function Binding(apiName) {
   this.apiName_ = apiName;
   this.apiFunctions_ = new APIFunctions(apiName);
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index fc0f7fd..fa67855 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -7094,7 +7094,7 @@
   def WriteGetDataSizeCode(self, func, f):
     """Overrriden from TypeHandler."""
     code = """  uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(%s), %d, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<%s, %d>(1, &data_size)) {
     return error::kOutOfBounds;
   }
 """
@@ -7392,7 +7392,7 @@
     """Overrriden from TypeHandler."""
     code = """  uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(%s), %d, &data_size)) {
+      !GLES2Util::ComputeDataSize<%s, %d>(count, &data_size)) {
     return error::kOutOfBounds;
   }
 """
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 8172e224..0a451f6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1820,22 +1820,6 @@
   return format;
 }
 
-// static
-bool GLES2Util::ComputeDataSize(uint32_t count,
-                                size_t size,
-                                unsigned int elements_per_unit,
-                                uint32_t* dst) {
-  uint32_t value;
-  if (!SafeMultiplyUint32(count, static_cast<uint32_t>(size), &value)) {
-    return false;
-  }
-  if (!SafeMultiplyUint32(value, elements_per_unit, &value)) {
-    return false;
-  }
-  *dst = value;
-  return true;
-}
-
 namespace {
 
 // GL context configuration attributes. Those in the 16-bit range are the same
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index f3dc765..e1b0c6ff 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -252,10 +252,12 @@
       uint32_t internal_format, uint32_t type, int* r, int* g, int* b, int* a);
 
   // Computes the data size for certain gl commands like glUniform.
-  static bool ComputeDataSize(uint32_t count,
-                              size_t size,
-                              unsigned int elements_per_unit,
-                              uint32_t* dst);
+  template <typename VALUE_TYPE, unsigned int ELEMENTS_PER_UNIT>
+  static bool ComputeDataSize(uint32_t count, uint32_t* dst) {
+    constexpr uint32_t element_size = sizeof(VALUE_TYPE) * ELEMENTS_PER_UNIT;
+    return base::CheckMul(count, element_size)
+        .template AssignIfValid<uint32_t>(dst);
+  }
 
 #include "gpu/command_buffer/common/gles2_cmd_utils_autogen.h"
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 8f57edf9..6b776d9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3179,6 +3179,10 @@
   context_ = context;
   surface_ = surface;
 
+  // Set workarounds for the surface.
+  surface_->SetRelyOnImplicitSync(
+      workarounds().rely_on_implicit_sync_for_swap_buffers);
+
   // Create GPU Tracer for timing values.
   gpu_tracer_.reset(new GPUTracer(this));
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 25237e2..fef99fa 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -387,7 +387,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -417,7 +417,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -447,7 +447,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2134,8 +2134,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2173,8 +2172,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2529,7 +2527,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2577,7 +2575,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2881,7 +2879,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2933,7 +2931,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3054,7 +3052,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3091,8 +3089,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3136,8 +3133,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3179,7 +3175,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3220,8 +3216,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3266,8 +3261,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3310,7 +3304,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3352,8 +3346,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3399,8 +3392,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3444,7 +3436,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3487,8 +3479,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3535,8 +3526,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3566,7 +3556,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3598,7 +3588,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3630,7 +3620,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3660,7 +3650,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 9>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3692,7 +3682,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3724,7 +3714,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3754,7 +3744,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 16>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3786,7 +3776,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3818,7 +3808,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3875,7 +3865,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3910,7 +3900,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 2>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3946,7 +3936,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 3>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3983,7 +3973,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4024,7 +4014,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4065,7 +4055,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4655,7 +4645,7 @@
       const volatile gles2::cmds::ProduceTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4685,7 +4675,7 @@
   GLuint texture = c.texture;
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4712,7 +4702,7 @@
       const volatile gles2::cmds::ConsumeTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4741,7 +4731,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLuint texture = static_cast<GLuint>(c.texture);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4833,8 +4823,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4888,8 +4877,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4916,8 +4904,7 @@
                        ScheduleCALayerInUseQueryCHROMIUMImmediate*>(cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4973,7 +4960,7 @@
 
   GLenum matrixMode = static_cast<GLenum>(c.matrixMode);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -5116,7 +5103,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -5155,8 +5142,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 629a24d..8a2d17d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -307,7 +307,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -334,7 +334,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -361,7 +361,7 @@
   GLenum buffer = static_cast<GLenum>(c.buffer);
   GLint drawbuffers = static_cast<GLint>(c.drawbuffers);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -1736,8 +1736,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -1767,8 +1766,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2120,7 +2118,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2162,7 +2160,7 @@
   GLuint sampler = c.sampler;
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2338,7 +2336,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2380,7 +2378,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLenum pname = static_cast<GLenum>(c.pname);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2471,7 +2469,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2511,8 +2509,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2552,8 +2549,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2595,7 +2591,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2636,8 +2632,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2678,8 +2673,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 2, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 2>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2722,7 +2716,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2764,8 +2758,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2807,8 +2800,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 3, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 3>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2852,7 +2844,7 @@
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2895,8 +2887,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2939,8 +2930,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2969,7 +2959,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -2998,7 +2988,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3027,7 +3017,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3056,7 +3046,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 9>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3085,7 +3075,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 6, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 6>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3114,7 +3104,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3143,7 +3133,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 16>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3172,7 +3162,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 8, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 8>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3201,7 +3191,7 @@
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size = 0;
   if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLfloat), 12, &data_size)) {
+      !GLES2Util::ComputeDataSize<GLfloat, 12>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3267,7 +3257,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 1>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3308,7 +3298,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 2>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3350,7 +3340,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 3>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3393,7 +3383,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3436,7 +3426,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3479,7 +3469,7 @@
           cmd_data);
   GLuint indx = static_cast<GLuint>(c.indx);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLuint), 4, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLuint, 4>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3908,7 +3898,7 @@
       const volatile gles2::cmds::ProduceTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3937,7 +3927,7 @@
   GLuint texture = c.texture;
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3962,7 +3952,7 @@
       const volatile gles2::cmds::ConsumeTextureCHROMIUMImmediate*>(cmd_data);
   GLenum target = static_cast<GLenum>(c.target);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -3990,7 +3980,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLuint texture = static_cast<GLuint>(c.texture);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLbyte), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLbyte, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4076,8 +4066,7 @@
   GLenum target = static_cast<GLenum>(c.target);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4118,8 +4107,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLenum, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4146,8 +4134,7 @@
                        ScheduleCALayerInUseQueryCHROMIUMImmediate*>(cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLuint), 1, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLuint, 1>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4206,7 +4193,7 @@
           cmd_data);
   GLenum matrixMode = static_cast<GLenum>(c.matrixMode);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4319,7 +4306,7 @@
   GLint location = static_cast<GLint>(c.location);
   GLboolean transpose = static_cast<GLboolean>(c.transpose);
   uint32_t data_size;
-  if (!GLES2Util::ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+  if (!GLES2Util::ComputeDataSize<GLfloat, 16>(1, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
@@ -4367,8 +4354,7 @@
           cmd_data);
   GLsizei count = static_cast<GLsizei>(c.count);
   uint32_t data_size = 0;
-  if (count >= 0 &&
-      !GLES2Util::ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+  if (count >= 0 && !GLES2Util::ComputeDataSize<GLint, 4>(count, &data_size)) {
     return error::kOutOfBounds;
   }
   if (data_size > immediate_data_size) {
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index d20ca2f..9576577 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -1,6 +1,6 @@
 {
   "name": "gpu driver bug list",
-  "version": "10.16",
+  "version": "10.17",
   "entries": [
     {
       "id": 1,
@@ -2552,6 +2552,18 @@
       "disabled_extensions": [
         "EGL_EXT_image_flush_external"
       ]
+    },
+    {
+      "id": 235,
+      "description": "Avoid waiting on a egl fence before pageflipping and rely on implicit sync.",
+      "cr_bugs": [721463],
+      "os": {
+        "type": "chromeos"
+      },
+      "gl_vendor": "Intel.*",
+      "features": [
+        "rely_on_implicit_sync_for_swap_buffers"
+      ]
     }
   ],
   "comment": [
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index f252881..ffe1402 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -225,6 +225,8 @@
          validate_multisample_buffer_allocation)             \
   GPU_OP(WAKE_UP_GPU_BEFORE_DRAWING,                         \
          wake_up_gpu_before_drawing)                         \
+  GPU_OP(RELY_ON_IMPLICIT_SYNC_FOR_SWAP_BUFFERS,             \
+         rely_on_implicit_sync_for_swap_buffers)             \
 // clang-format on
 
 namespace gpu {
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 0473879..09d3bd247 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1236,6 +1236,9 @@
       <message name="IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME" desc="Label indicating that the text displayed below is the username to which a saved password corresponds. The password is displayed in the same view, but under a diferent label. [Length: 20em] [iOS only]">
         Username
       </message>
+      <message name="IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION" desc="Label indicating that the text displayed below is the hostname of the identity provider used for the displayed credential. [Length: to fit on one line] [iOS only]">
+        With Federation
+      </message>
       <message name="IDS_IOS_CANCEL_PASSWORD_DELETION" desc="Label of a confirmation dialogue button which allows the user to cancel deletion of a stored password. [Length: one line] [iOS only]">
         Cancel
       </message>
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index d32ac78..45e719f 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -43,6 +43,7 @@
 
 using chrome_test_util::OpenLinkInNewTabButton;
 using chrome_test_util::SettingsMenuButton;
+using chrome_test_util::SettingsMenuPrivacyButton;
 using tab_usage_recorder_test_util::OpenNewIncognitoTabUsingUIAndEvictMainTabs;
 using tab_usage_recorder_test_util::SwitchToNormalMode;
 
@@ -131,16 +132,6 @@
       @"Waiting for tab to close");
 }
 
-// Open the settings submenu. Assumes that settings menu is visible.
-void OpenSettingsSubMenuUnsynced(int submenu) {
-  id<GREYMatcher> settings_button_matcher =
-      grey_text(l10n_util::GetNSString(submenu));
-  [[[EarlGrey selectElementWithMatcher:settings_button_matcher]
-         usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
-      onElementWithMatcher:grey_accessibilityID(kSettingsCollectionViewId)]
-      performAction:grey_tap()];
-}
-
 // Open the settings menu. Wait for the settings menu to appear.
 void OpenSettingsMenuUnsynced() {
   id<GREYMatcher> tool_menu_matcher =
@@ -514,7 +505,7 @@
           setValue:@(NO)
       forConfigKey:kGREYConfigKeySynchronizationEnabled];
   OpenSettingsMenuUnsynced();
-  OpenSettingsSubMenuUnsynced(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   Wait(grey_accessibilityID(kPrivacyCollectionViewId),
        @"Privacy settings view.");
 
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
index f4bcf98..7391594 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory_unittest.cc
@@ -48,6 +48,7 @@
     datatypes.push_back(syncer::SESSIONS);
     datatypes.push_back(syncer::PROXY_TABS);
     datatypes.push_back(syncer::TYPED_URLS);
+    datatypes.push_back(syncer::USER_EVENTS);
 
     return datatypes;
   }
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 13fa521..102d2a0 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -38,6 +38,7 @@
 #include "components/sync/engine/passive_model_worker.h"
 #include "components/sync/engine/sequenced_model_worker.h"
 #include "components/sync/engine/ui_model_worker.h"
+#include "components/sync/user_events/user_event_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/sync_sessions/favicon_cache.h"
 #include "components/sync_sessions/local_session_event_router.h"
@@ -59,6 +60,7 @@
 #include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
 #include "ios/chrome/browser/sync/glue/sync_start_util.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/ios_user_event_service_factory.h"
 #include "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h"
 #include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h"
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
@@ -364,6 +366,10 @@
       // TODO(gangwu):implement TypedURLSyncBridge and return real
       // TypedURLSyncBridge here.
       return base::WeakPtr<syncer::ModelTypeSyncBridge>();
+    case syncer::USER_EVENTS:
+      return IOSUserEventServiceFactory::GetForBrowserState(browser_state_)
+          ->GetSyncBridge()
+          ->AsWeakPtr();
     default:
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeSyncBridge>();
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_egtest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_egtest.mm
index 38307d3..abaa8ea 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data_egtest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data_egtest.mm
@@ -20,6 +20,7 @@
 using chrome_test_util::ButtonWithAccessibilityLabel;
 using chrome_test_util::ButtonWithAccessibilityLabelId;
 using chrome_test_util::NavigationBarDoneButton;
+using chrome_test_util::SettingsMenuPrivacyButton;
 
 @interface ClearBrowsingDataSettingsTestCase : ChromeTestCase
 @end
@@ -28,11 +29,7 @@
 
 - (void)openClearBrowsingDataDialog {
   [ChromeEarlGreyUI openSettingsMenu];
-  NSString* settingsLabel =
-      l10n_util::GetNSString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
-  [[EarlGrey
-      selectElementWithMatcher:ButtonWithAccessibilityLabel(settingsLabel)]
-      performAction:grey_tap()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
 
   NSString* clearBrowsingDataDialogLabel =
       l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE);
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
index 5f1ed06..d2c9c7a 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -39,6 +39,7 @@
   SectionIdentifierSite = kSectionIdentifierEnumZero,
   SectionIdentifierUsername,
   SectionIdentifierPassword,
+  SectionIdentifierFederation,
   SectionIdentifierDelete,
 };
 
@@ -51,6 +52,7 @@
   ItemTypePassword,
   ItemTypeCopyPassword,
   ItemTypeShowHide,
+  ItemTypeFederation,
   ItemTypeDelete,
 };
 
@@ -72,6 +74,8 @@
   NSString* _username;
   // The saved password.
   NSString* _password;
+  // The federation providing this credential, if any.
+  NSString* _federation;
   // The origin site of the saved credential.
   NSString* _site;
   // Whether the password is shown in plain text form or in obscured form.
@@ -115,7 +119,12 @@
     _passwordForm = passwordForm;
     if (!_passwordForm.blacklisted_by_user) {
       _username = base::SysUTF16ToNSString(_passwordForm.username_value);
-      _password = base::SysUTF16ToNSString(_passwordForm.password_value);
+      if (_passwordForm.federation_origin.unique()) {
+        _password = base::SysUTF16ToNSString(_passwordForm.password_value);
+      } else {
+        _federation =
+            base::SysUTF8ToNSString(_passwordForm.federation_origin.host());
+      }
     }
     _site = base::SysUTF8ToNSString(_passwordForm.origin.spec());
     self.title = [PasswordDetailsCollectionViewController
@@ -185,24 +194,42 @@
     [model addItem:[self usernameCopyButtonItem]
         toSectionWithIdentifier:SectionIdentifierUsername];
 
-    [model addSectionWithIdentifier:SectionIdentifierPassword];
-    CollectionViewTextItem* passwordHeader =
-        [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
-    passwordHeader.text =
-        l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
-    passwordHeader.textColor = [[MDCPalette greyPalette] tint500];
-    [model setHeader:passwordHeader
-        forSectionWithIdentifier:SectionIdentifierPassword];
-    _passwordItem = [[PasswordDetailsItem alloc] initWithType:ItemTypePassword];
-    _passwordItem.text = _password;
-    _passwordItem.showingText = NO;
-    [model addItem:_passwordItem
-        toSectionWithIdentifier:SectionIdentifierPassword];
+    if (_passwordForm.federation_origin.unique()) {
+      [model addSectionWithIdentifier:SectionIdentifierPassword];
+      CollectionViewTextItem* passwordHeader =
+          [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
+      passwordHeader.text =
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
+      passwordHeader.textColor = [[MDCPalette greyPalette] tint500];
+      [model setHeader:passwordHeader
+          forSectionWithIdentifier:SectionIdentifierPassword];
+      _passwordItem =
+          [[PasswordDetailsItem alloc] initWithType:ItemTypePassword];
+      _passwordItem.text = _password;
+      _passwordItem.showingText = NO;
+      [model addItem:_passwordItem
+          toSectionWithIdentifier:SectionIdentifierPassword];
 
-    [model addItem:[self passwordCopyButtonItem]
-        toSectionWithIdentifier:SectionIdentifierPassword];
-    [model addItem:[self showHidePasswordButtonItem]
-        toSectionWithIdentifier:SectionIdentifierPassword];
+      [model addItem:[self passwordCopyButtonItem]
+          toSectionWithIdentifier:SectionIdentifierPassword];
+      [model addItem:[self showHidePasswordButtonItem]
+          toSectionWithIdentifier:SectionIdentifierPassword];
+    } else {
+      [model addSectionWithIdentifier:SectionIdentifierFederation];
+      CollectionViewTextItem* federationHeader =
+          [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
+      federationHeader.text =
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION);
+      federationHeader.textColor = [[MDCPalette greyPalette] tint500];
+      [model setHeader:federationHeader
+          forSectionWithIdentifier:SectionIdentifierFederation];
+      PasswordDetailsItem* federationItem =
+          [[PasswordDetailsItem alloc] initWithType:ItemTypeFederation];
+      federationItem.text = _federation;
+      federationItem.showingText = YES;
+      [model addItem:federationItem
+          toSectionWithIdentifier:SectionIdentifierFederation];
+    }
   }
 
   [model addSectionWithIdentifier:SectionIdentifierDelete];
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
index f7a56e6..88b95945 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
@@ -190,6 +190,62 @@
                            kBlacklistedDeleteButtonItem);
 }
 
+TEST_F(PasswordDetailsCollectionViewControllerTest,
+       TestInitialization_Federated) {
+  constexpr int kFederatedSiteSection = 0;
+  constexpr int kFederatedSiteItem = 0;
+  constexpr int kFederatedCopySiteButtonItem = 1;
+
+  constexpr int kFederatedUsernameSection = 1;
+  constexpr int kFederatedUsernameItem = 0;
+  constexpr int kFederatedCopyUsernameButtonItem = 1;
+
+  constexpr int kFederatedFederationSection = 2;
+  constexpr int kFederatedFederationItem = 0;
+
+  constexpr int kFederatedDeleteSection = 3;
+  constexpr int kFederatedDeleteButtonItem = 0;
+
+  form_.password_value.clear();
+  form_.federation_origin = url::Origin(GURL("https://famous.provider.net"));
+  CreateController();
+  CheckController();
+  EXPECT_EQ(4, NumberOfSections());
+  // Site section
+  EXPECT_EQ(2, NumberOfItemsInSection(kFederatedSiteSection));
+  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_SITE,
+                           kFederatedSiteSection);
+  PasswordDetailsItem* siteItem =
+      GetCollectionViewItem(kFederatedSiteSection, kFederatedSiteItem);
+  EXPECT_NSEQ(origin_, siteItem.text);
+  EXPECT_TRUE(siteItem.showingText);
+  CheckTextCellTitleWithId(IDS_IOS_SETTINGS_SITE_COPY_BUTTON,
+                           kFederatedSiteSection, kFederatedCopySiteButtonItem);
+  // Username section
+  EXPECT_EQ(2, NumberOfItemsInSection(kFederatedUsernameSection));
+  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME,
+                           kFederatedUsernameSection);
+  PasswordDetailsItem* usernameItem =
+      GetCollectionViewItem(kFederatedUsernameSection, kFederatedUsernameItem);
+  EXPECT_NSEQ(kUsername, usernameItem.text);
+  EXPECT_TRUE(usernameItem.showingText);
+  CheckTextCellTitleWithId(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON,
+                           kFederatedUsernameSection,
+                           kFederatedCopyUsernameButtonItem);
+  // Federated section
+  EXPECT_EQ(1, NumberOfItemsInSection(kFederatedFederationSection));
+  CheckSectionHeaderWithId(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION,
+                           kFederatedFederationSection);
+  PasswordDetailsItem* federationItem = GetCollectionViewItem(
+      kFederatedFederationSection, kFederatedFederationItem);
+  EXPECT_NSEQ(@"famous.provider.net", federationItem.text);
+  EXPECT_TRUE(federationItem.showingText);
+  // Delete section
+  EXPECT_EQ(1, NumberOfItemsInSection(kFederatedDeleteSection));
+  CheckTextCellTitleWithId(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON,
+                           kFederatedDeleteSection, kFederatedDeleteButtonItem);
+}
+
 struct SimplifyOriginTestData {
   GURL origin;
   NSString* expectedSimplifiedOrigin;
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index 00644ad..555818db 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -32,6 +32,7 @@
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -895,4 +896,70 @@
   [self clearPasswordStore];
 }
 
+// Checks that federated credentials have no password but show the federation.
+- (void)testFederated {
+  [self scopedEnablePasswordManagementAndViewingUI];
+
+  PasswordForm federated;
+  federated.username_value = base::ASCIIToUTF16("federated username");
+  federated.origin = GURL("https://example.com");
+  federated.signon_realm = federated.origin.spec();
+  federated.federation_origin =
+      url::Origin(GURL("https://famous.provider.net"));
+  [self savePasswordFormToStore:federated];
+
+  [self openPasswordSettings];
+
+  [[EarlGrey
+      selectElementWithMatcher:Entry(
+                                   @"https://example.com, federated username")]
+      performAction:grey_tap()];
+
+  // Check that the Site, Username, Federation and Delete Saved Password
+  // sections are there. (No scrolling for the first two, which should be high
+  // enough to always start visible.)
+  [[EarlGrey selectElementWithMatcher:SiteHeader()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:UsernameHeader()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  // For federation check both the section header and content.
+  [[[EarlGrey
+      selectElementWithMatcher:
+          grey_allOf(grey_accessibilityTrait(UIAccessibilityTraitHeader),
+                     grey_accessibilityLabel(l10n_util::GetNSString(
+                         IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION)),
+                     nullptr)]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown,
+                                                  kScrollAmount)
+      onElementWithMatcher:grey_accessibilityID(
+                               @"PasswordDetailsCollectionViewController")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[[EarlGrey selectElementWithMatcher:grey_text(@"famous.provider.net")]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown,
+                                                  kScrollAmount)
+      onElementWithMatcher:grey_accessibilityID(
+                               @"PasswordDetailsCollectionViewController")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  // Not using DeleteButton() matcher here, because that also encodes the
+  // relative position against the password section, which is missing in this
+  // case.
+  [[[EarlGrey selectElementWithMatcher:
+                  ButtonWithAccessibilityLabel(l10n_util::GetNSString(
+                      IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON))]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown,
+                                                  kScrollAmount)
+      onElementWithMatcher:grey_accessibilityID(
+                               @"PasswordDetailsCollectionViewController")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Check that the password is not present.
+  [[EarlGrey selectElementWithMatcher:PasswordHeader()]
+      assertWithMatcher:grey_nil()];
+
+  [self tapBackArrow];
+  [self tapBackArrow];
+  [self tapDone];
+  [self clearPasswordStore];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/settings_egtest.mm b/ios/chrome/browser/ui/settings/settings_egtest.mm
index 8c9bce1..cad68a0 100644
--- a/ios/chrome/browser/ui/settings/settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/settings_egtest.mm
@@ -61,6 +61,7 @@
 using chrome_test_util::ContentSettingsButton;
 using chrome_test_util::NavigationBarDoneButton;
 using chrome_test_util::SettingsMenuBackButton;
+using chrome_test_util::SettingsMenuPrivacyButton;
 
 namespace {
 
@@ -110,11 +111,6 @@
 id<GREYMatcher> PasswordsButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_SAVE_PASSWORDS);
 }
-// Matcher for the Privacy cell on the main Settings screen.
-id<GREYMatcher> PrivacyButton() {
-  return ButtonWithAccessibilityLabelId(
-      IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
-}
 // Matcher for the Send Usage Data cell on the Privacy screen.
 id<GREYMatcher> SendUsageDataButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_OPTIONS_SEND_USAGE_DATA);
@@ -307,7 +303,7 @@
 // From the NTP, clears the cookies and site data via the UI.
 - (void)clearCookiesAndSiteData {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   [ChromeEarlGreyUI tapPrivacyMenuButton:ClearBrowsingDataCell()];
 
   // "Browsing history", "Cookies, Site Data" and "Cached Images and Files"
@@ -326,7 +322,7 @@
 // From the NTP, clears the saved passwords via the UI.
 - (void)clearPasswords {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   [ChromeEarlGreyUI tapPrivacyMenuButton:ClearBrowsingDataCell()];
 
   // "Browsing history", "Cookies, Site Data" and "Cached Images and Files"
@@ -817,7 +813,7 @@
 // Verifies the UI elements are accessible on the Privacy Settings page.
 - (void)testAccessibilityOnPrivacySettingsPage {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
   [self closeSubSettingsMenu];
 }
@@ -826,7 +822,7 @@
 // page.
 - (void)testAccessibilityOnPrivacyHandoffSettingsPage {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   [[EarlGrey selectElementWithMatcher:PrivacyHandoffButton()]
       performAction:grey_tap()];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
@@ -837,7 +833,7 @@
 // Settings page.
 - (void)testAccessibilityOnPrivacyClearBrowsingHistoryPage {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   [ChromeEarlGreyUI tapPrivacyMenuButton:ClearBrowsingDataButton()];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
   [self closeSubSettingsMenu];
@@ -985,7 +981,7 @@
 // Verifies the UI elements are accessible on the Send Usage Data page.
 - (void)testAccessibilityOnSendUsageData {
   [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:PrivacyButton()];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsMenuPrivacyButton()];
   [ChromeEarlGreyUI tapPrivacyMenuButton:SendUsageDataButton()];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
   [self closeSubSettingsMenu];
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index 5806909..e453735 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -472,6 +472,9 @@
   [toolsCell.reloadButton removeTarget:self.dispatcher
                                 action:@selector(reload)
                       forControlEvents:UIControlEventTouchUpInside];
+  [toolsCell.shareButton removeTarget:self.dispatcher
+                               action:@selector(sharePage)
+                     forControlEvents:UIControlEventTouchUpInside];
   [toolsCell.starButton removeTarget:self.dispatcher
                               action:@selector(bookmarkPage)
                     forControlEvents:UIControlEventTouchUpInside];
@@ -595,6 +598,9 @@
     [cell.reloadButton addTarget:self.dispatcher
                           action:@selector(reload)
                 forControlEvents:UIControlEventTouchUpInside];
+    [cell.shareButton addTarget:self.dispatcher
+                         action:@selector(sharePage)
+               forControlEvents:UIControlEventTouchUpInside];
     [cell.starButton addTarget:self.dispatcher
                         action:@selector(bookmarkPage)
               forControlEvents:UIControlEventTouchUpInside];
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index ec003bd..02ec694d 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -120,6 +120,9 @@
 // Returns matcher for the back button on a settings menu.
 id<GREYMatcher> SettingsMenuBackButton();
 
+// Returns matcher for the Privacy cell on the main Settings screen.
+id<GREYMatcher> SettingsMenuPrivacyButton();
+
 }  // namespace chrome_test_util
 
 #endif  // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index 67beef5..31ebd9cc 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -214,4 +214,9 @@
                     grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
 }
 
+id<GREYMatcher> SettingsMenuPrivacyButton() {
+  return ButtonWithAccessibilityLabelId(
+      IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
+}
+
 }  // namespace chrome_test_util
diff --git a/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn b/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn
index e9bb6bd..7bdd24da 100644
--- a/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab_collection/BUILD.gn
@@ -29,11 +29,13 @@
   ]
   deps = [
     "//base",
+    "//components/strings:components_strings_grit",
     "//ios/chrome/app/theme:theme_grit",
     "//ios/chrome/browser/snapshots",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/tab_switcher",
     "//ios/clean/chrome/browser/ui/commands",
+    "//ui/base",
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.mm
index 2dddb649..35ecae805 100644
--- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.mm
+++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.mm
@@ -4,6 +4,10 @@
 
 #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.h"
 
+#include "base/logging.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -11,4 +15,19 @@
 @implementation TabCollectionItem
 @synthesize tabID = _tabID;
 @synthesize title = _title;
+
+#pragma mark - Public properties
+
+- (void)setTabID:(NSString*)tabID {
+  DCHECK_GE(tabID.length, 0U);
+  _tabID = tabID;
+}
+
+- (void)setTitle:(NSString*)title {
+  _title = title;
+  if (title.length == 0) {
+    _title = l10n_util::GetNSString(IDS_DEFAULT_TAB_TITLE);
+  }
+}
+
 @end
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm
index ae3a900c..d99ad20 100644
--- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm
+++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm
@@ -139,18 +139,12 @@
 
 // Constructs a TabCollectionItem from a |webState|.
 - (TabCollectionItem*)tabCollectionItemFromWebState:(web::WebState*)webState {
-  // PLACEHOLDER: Use real webstate title in the future.
   DCHECK(webState);
-  GURL url = webState->GetVisibleURL();
-  NSString* urlText = @"<New Tab>";
-  if (url.is_valid()) {
-    urlText = base::SysUTF8ToNSString(url.spec());
-  }
   TabIdTabHelper* tabHelper = TabIdTabHelper::FromWebState(webState);
   DCHECK(tabHelper);
   TabCollectionItem* item = [[TabCollectionItem alloc] init];
   item.tabID = tabHelper->tab_id();
-  item.title = urlText;
+  item.title = base::SysUTF16ToNSString(webState->GetTitle());
   return item;
 }
 
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm
index 2367e1c4..686b367 100644
--- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm
+++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm
@@ -64,9 +64,7 @@
                        callback:^(UIImage* snapshot) {
                          // PLACEHOLDER: This operation will be cancellable.
                          if ([weakSelf.item.tabID isEqualToString:item.tabID]) {
-                           [weakSelf.snapshotButton
-                               setImage:snapshot
-                               forState:UIControlStateNormal];
+                           [weakSelf setSnapshot:snapshot];
                          }
                        }];
 }
diff --git a/ios/web/payments/payment_request.cc b/ios/web/payments/payment_request.cc
index 7798b25..d0aef08 100644
--- a/ios/web/payments/payment_request.cc
+++ b/ios/web/payments/payment_request.cc
@@ -4,6 +4,7 @@
 
 #include "ios/web/public/payments/payment_request.h"
 
+#include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 
@@ -362,7 +363,13 @@
 
   result->SetString(kPaymentRequestId, this->payment_request_id);
   result->SetString(kPaymentResponseMethodName, this->method_name);
-  result->SetString(kPaymentResponseDetails, this->details);
+  // |this.details| is a json-serialized string. Parse it to a base::Value so
+  // that when |this| is converted to a JSON string, |this.details| won't get
+  // json-escaped.
+  std::unique_ptr<base::Value> details =
+      base::JSONReader().ReadToValue(this->details);
+  if (details)
+    result->Set(kPaymentResponseDetails, std::move(details));
   if (!this->shipping_address.ToDictionaryValue()->empty()) {
     result->Set(kPaymentResponseShippingAddress,
                 this->shipping_address.ToDictionaryValue());
diff --git a/ios/web/payments/payment_request_unittest.cc b/ios/web/payments/payment_request_unittest.cc
index c80ccc4..1552ff41 100644
--- a/ios/web/payments/payment_request_unittest.cc
+++ b/ios/web/payments/payment_request_unittest.cc
@@ -264,7 +264,6 @@
 TEST(PaymentRequestTest, EmptyResponseDictionary) {
   base::DictionaryValue expected_value;
 
-  expected_value.SetString("details", "");
   expected_value.SetString("paymentRequestID", "");
   expected_value.SetString("methodName", "");
 
@@ -288,9 +287,7 @@
       new base::DictionaryValue);
   billing_address->SetString("postalCode", "90210");
   details->Set("billingAddress", std::move(billing_address));
-  std::string stringified_details;
-  base::JSONWriter::Write(*details, &stringified_details);
-  expected_value.SetString("details", stringified_details);
+  expected_value.Set("details", std::move(details));
   expected_value.SetString("paymentRequestID", "12345");
   expected_value.SetString("methodName", "American Express");
   std::unique_ptr<base::DictionaryValue> shipping_address(
diff --git a/ios/web/public/payments/payment_request.h b/ios/web/public/payments/payment_request.h
index 76e80fe2..4952bd5 100644
--- a/ios/web/public/payments/payment_request.h
+++ b/ios/web/public/payments/payment_request.h
@@ -262,8 +262,8 @@
   // to fulfil the transaction.
   base::string16 method_name;
 
-  // A credit card response object used by the merchant to process the
-  // transaction and determine successful fund transfer.
+  // The json-serialized stringified details of the payment method. Used by the
+  // merchant to process the transaction and determine successful fund transfer.
   std::string details;
 
   // If request_shipping was set to true in the PaymentOptions passed to the
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index a81541eb..0e71e2a 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -5057,16 +5057,21 @@
     [request setHTTPMethod:@"POST"];
     [request setHTTPBody:POSTData];
     [request setAllHTTPHeaderFields:self.currentHTTPHeaders];
-    GURL navigationURL =
-        currentItem ? currentItem->GetURL() : GURL::EmptyGURL();
-    std::unique_ptr<web::NavigationContextImpl> navigationContext =
-        [self registerLoadRequestForURL:navigationURL
-                               referrer:self.currentNavItemReferrer
-                             transition:self.currentTransition];
-    WKNavigation* navigation = [self loadPOSTRequest:request];
-    [_navigationStates setContext:std::move(navigationContext)
-                    forNavigation:navigation];
-    return;
+    // As of iOS 11, WKWebView supports requests with POST data, so the
+    // Javascript POST workaround only needs to be used if the OS version is
+    // less than iOS 11.
+    if (!base::ios::IsRunningOnIOS11OrLater()) {
+      GURL navigationURL =
+          currentItem ? currentItem->GetURL() : GURL::EmptyGURL();
+      std::unique_ptr<web::NavigationContextImpl> navigationContext =
+          [self registerLoadRequestForURL:navigationURL
+                                 referrer:self.currentNavItemReferrer
+                               transition:self.currentTransition];
+      WKNavigation* navigation = [self loadPOSTRequest:request];
+      [_navigationStates setContext:std::move(navigationContext)
+                      forNavigation:navigation];
+      return;
+    }
   }
 
   ProceduralBlock defaultNavigationBlock = ^{
diff --git a/ios/web_view/internal/cwv_web_view_configuration.mm b/ios/web_view/internal/cwv_web_view_configuration.mm
index d123fbf3..736dfbb 100644
--- a/ios/web_view/internal/cwv_web_view_configuration.mm
+++ b/ios/web_view/internal/cwv_web_view_configuration.mm
@@ -7,7 +7,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_restrictions.h"
-#include "components/translate/core/browser/translate_download_manager.h"
 #include "ios/web_view/internal/app/application_context.h"
 #import "ios/web_view/internal/cwv_user_content_controller_internal.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
@@ -32,14 +31,27 @@
 @synthesize userContentController = _userContentController;
 
 + (instancetype)defaultConfiguration {
-  auto browserState =
-      base::MakeUnique<ios_web_view::WebViewBrowserState>(false);
-  return [[self alloc] initWithBrowserState:std::move(browserState)];
+  static CWVWebViewConfiguration* defaultConfiguration;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    auto browserState =
+        base::MakeUnique<ios_web_view::WebViewBrowserState>(false);
+    defaultConfiguration =
+        [[self alloc] initWithBrowserState:std::move(browserState)];
+  });
+  return defaultConfiguration;
 }
 
 + (instancetype)incognitoConfiguration {
-  auto browserState = base::MakeUnique<ios_web_view::WebViewBrowserState>(true);
-  return [[self alloc] initWithBrowserState:std::move(browserState)];
+  static CWVWebViewConfiguration* incognitoConfiguration;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    auto browserState =
+        base::MakeUnique<ios_web_view::WebViewBrowserState>(true);
+    incognitoConfiguration =
+        [[self alloc] initWithBrowserState:std::move(browserState)];
+  });
+  return incognitoConfiguration;
 }
 
 + (void)initialize {
@@ -62,10 +74,14 @@
   return self;
 }
 
+#pragma mark - Public Methods
+
 - (BOOL)isPersistent {
   return !_browserState->IsOffTheRecord();
 }
 
+#pragma mark - Private Methods
+
 - (ios_web_view::WebViewBrowserState*)browserState {
   return _browserState.get();
 }
diff --git a/ios/web_view/internal/translate/cwv_translation_controller.mm b/ios/web_view/internal/translate/cwv_translation_controller.mm
index c62a868..17ed9e9 100644
--- a/ios/web_view/internal/translate/cwv_translation_controller.mm
+++ b/ios/web_view/internal/translate/cwv_translation_controller.mm
@@ -11,8 +11,11 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
+#import "ios/web_view/internal/cwv_web_view_configuration_internal.h"
+#include "ios/web_view/internal/pref_names.h"
 #import "ios/web_view/internal/translate/cwv_translation_language_internal.h"
 #import "ios/web_view/internal/translate/web_view_translate_client.h"
+#include "ios/web_view/internal/web_view_browser_state.h"
 #import "ios/web_view/public/cwv_translation_controller_delegate.h"
 #import "ios/web_view/public/cwv_translation_policy.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -65,6 +68,17 @@
 @synthesize supportedLanguagesByCode = _supportedLanguagesByCode;
 @synthesize webState = _webState;
 
+#pragma mark - Class Methods
+
++ (void)resetTranslationPolicies {
+  CWVWebViewConfiguration* configuration =
+      [CWVWebViewConfiguration defaultConfiguration];
+  PrefService* prefService = configuration.browserState->GetPrefs();
+  translate::TranslatePrefs translatePrefs(prefService, prefs::kAcceptLanguages,
+                                           nullptr);
+  translatePrefs.ResetToDefaults();
+}
+
 #pragma mark - Internal Methods
 
 - (void)setWebState:(web::WebState*)webState {
@@ -155,6 +169,7 @@
 
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
              forPageLanguage:(CWVTranslationLanguage*)pageLanguage {
+  DCHECK(!_webState->GetBrowserState()->IsOffTheRecord());
   std::string languageCode = base::SysNSStringToUTF8(pageLanguage.languageCode);
   switch (policy.type) {
     case CWVTranslationPolicyAsk: {
@@ -198,6 +213,7 @@
 
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
                  forPageHost:(NSString*)pageHost {
+  DCHECK(!_webState->GetBrowserState()->IsOffTheRecord());
   DCHECK(pageHost.length);
   switch (policy.type) {
     case CWVTranslationPolicyAsk: {
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index bdc2c63e..37e963fd 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -8,11 +8,13 @@
 
 #include "base/base_paths.h"
 #include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/in_memory_pref_store.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_filter.h"
 #include "components/prefs/pref_service_factory.h"
@@ -56,8 +58,13 @@
       JsonPrefStore::GetTaskRunnerForFile(path_,
                                           web::WebThread::GetBlockingPool());
 
-  scoped_refptr<PersistentPrefStore> user_pref_store = new JsonPrefStore(
-      path_.Append(kPreferencesFilename), sequenced_task_runner, nullptr);
+  scoped_refptr<PersistentPrefStore> user_pref_store;
+  if (off_the_record) {
+    user_pref_store = new InMemoryPrefStore();
+  } else {
+    user_pref_store = new JsonPrefStore(path_.Append(kPreferencesFilename),
+                                        sequenced_task_runner, nullptr);
+  }
 
   PrefServiceFactory factory;
   factory.set_user_prefs(user_pref_store);
diff --git a/ios/web_view/public/cwv_translation_controller.h b/ios/web_view/public/cwv_translation_controller.h
index ee31066..6e9476d 100644
--- a/ios/web_view/public/cwv_translation_controller.h
+++ b/ios/web_view/public/cwv_translation_controller.h
@@ -52,6 +52,10 @@
 @property(nonatomic, readonly)
     NSSet<CWVTranslationLanguage*>* supportedLanguages;
 
+// Resets all translation policies to default (CWVTranslationPolicyAsk).
+// Only resets non-incognito settings.
++ (void)resetTranslationPolicies;
+
 // Begins translation on the current page from |sourceLanguage| to
 // |targetLanguage|. These language parameters must be chosen from
 // |supportedLanguages|. Set |userInitiated| to YES if translation
@@ -70,6 +74,7 @@
 
 // Sets or retrieves translation policies associated with a specified language.
 // |pageLanguage| should be the language code of the language.
+// Not supported in incognito mode.
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
              forPageLanguage:(CWVTranslationLanguage*)pageLanguage;
 - (CWVTranslationPolicy*)translationPolicyForPageLanguage:
@@ -77,6 +82,7 @@
 
 // Sets or retrieves translation policies associated with a specified page.
 // |pageHost| should be the hostname of the website. Must not be empty.
+// Not supported in incognito mode.
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
                  forPageHost:(NSString*)pageHost;
 - (CWVTranslationPolicy*)translationPolicyForPageHost:(NSString*)pageHost;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index cf02d45..2264be19 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -55,6 +55,8 @@
   MOCK_METHOD2(OnAddTextTrack,
                void(const TextTrackConfig&, const AddTextTrackDoneCB&));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void());
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
   MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void());
@@ -236,6 +238,8 @@
   MOCK_METHOD1(OnStatisticsUpdate, void(const PipelineStatistics&));
   MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void());
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
   MOCK_METHOD1(OnDurationChange, void(base::TimeDelta));
diff --git a/media/base/pipeline.h b/media/base/pipeline.h
index c85fb90..1423afae 100644
--- a/media/base/pipeline.h
+++ b/media/base/pipeline.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/buffering_state.h"
 #include "media/base/cdm_context.h"
 #include "media/base/media_export.h"
@@ -17,6 +18,7 @@
 #include "media/base/pipeline_status.h"
 #include "media/base/ranges.h"
 #include "media/base/text_track.h"
+#include "media/base/video_decoder_config.h"
 #include "media/base/video_rotation.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -65,6 +67,11 @@
 
     // Executed when the average keyframe distance for the video changes.
     virtual void OnVideoAverageKeyframeDistanceUpdate() = 0;
+
+    // Executed whenever DemuxerStream status returns kConfigChange. Initial
+    // configs provided by OnMetadata.
+    virtual void OnAudioConfigChange(const AudioDecoderConfig& config) = 0;
+    virtual void OnVideoConfigChange(const VideoDecoderConfig& config) = 0;
   };
 
   virtual ~Pipeline() {}
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 479e72c..ecf1574 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -121,6 +121,8 @@
   void OnStatisticsUpdate(const PipelineStatistics& stats) final;
   void OnBufferingStateChange(BufferingState state) final;
   void OnWaitingForDecryptionKey() final;
+  void OnAudioConfigChange(const AudioDecoderConfig& config) final;
+  void OnVideoConfigChange(const VideoDecoderConfig& config) final;
   void OnVideoNaturalSizeChange(const gfx::Size& size) final;
   void OnVideoOpacityChange(bool opaque) final;
   void OnDurationChange(base::TimeDelta duration) final;
@@ -705,6 +707,24 @@
       base::Bind(&PipelineImpl::OnVideoOpacityChange, weak_pipeline_, opaque));
 }
 
+void PipelineImpl::RendererWrapper::OnAudioConfigChange(
+    const AudioDecoderConfig& config) {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineImpl::OnAudioConfigChange, weak_pipeline_, config));
+}
+
+void PipelineImpl::RendererWrapper::OnVideoConfigChange(
+    const VideoDecoderConfig& config) {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineImpl::OnVideoConfigChange, weak_pipeline_, config));
+}
+
 void PipelineImpl::RendererWrapper::OnDurationChange(base::TimeDelta duration) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   SetDuration(duration);
@@ -1344,6 +1364,24 @@
   client_->OnVideoOpacityChange(opaque);
 }
 
+void PipelineImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
+  DVLOG(2) << __func__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(IsRunning());
+
+  DCHECK(client_);
+  client_->OnAudioConfigChange(config);
+}
+
+void PipelineImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
+  DVLOG(2) << __func__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(IsRunning());
+
+  DCHECK(client_);
+  client_->OnVideoConfigChange(config);
+}
+
 void PipelineImpl::OnVideoAverageKeyframeDistanceUpdate() {
   DVLOG(2) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h
index d04ca0d..e5c9de3 100644
--- a/media/base/pipeline_impl.h
+++ b/media/base/pipeline_impl.h
@@ -133,6 +133,8 @@
   void OnAddTextTrack(const TextTrackConfig& config,
                       const AddTextTrackDoneCB& done_cb);
   void OnWaitingForDecryptionKey();
+  void OnAudioConfigChange(const AudioDecoderConfig& config);
+  void OnVideoConfigChange(const VideoDecoderConfig& config);
   void OnVideoNaturalSizeChange(const gfx::Size& size);
   void OnVideoOpacityChange(bool opaque);
   void OnVideoAverageKeyframeDistanceUpdate();
diff --git a/media/base/renderer_client.h b/media/base/renderer_client.h
index 402c31b..3fc8919 100644
--- a/media/base/renderer_client.h
+++ b/media/base/renderer_client.h
@@ -6,7 +6,9 @@
 #define MEDIA_BASE_RENDERER_CLIENT_H_
 
 #include "base/time/time.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/pipeline_status.h"
+#include "media/base/video_decoder_config.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
@@ -30,12 +32,17 @@
   // Executed whenever the key needed to decrypt the stream is not available.
   virtual void OnWaitingForDecryptionKey() = 0;
 
+  // Executed whenever DemuxerStream status returns kConfigChange. Initial
+  // configs provided by OnMetadata.
+  virtual void OnAudioConfigChange(const AudioDecoderConfig& config) = 0;
+  virtual void OnVideoConfigChange(const VideoDecoderConfig& config) = 0;
+
   // Executed for the first video frame and whenever natural size changes.
-  // Only used if media stream contains video track.
+  // Only used if media stream contains a video track.
   virtual void OnVideoNaturalSizeChange(const gfx::Size& size) = 0;
 
   // Executed for the first video frame and whenever opacity changes.
-  // Only used if media stream contains video track.
+  // Only used if media stream contains a video track.
   virtual void OnVideoOpacityChange(bool opaque) = 0;
 
   // Executed when video metadata is first read, and whenever it changes.
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index dc0ff01..181c7b4 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -157,6 +157,11 @@
 bool VerifyFakeVideoBufferForTest(const scoped_refptr<DecoderBuffer>& buffer,
                                   const VideoDecoderConfig& config);
 
+// Compares two {Audio|Video}DecoderConfigs
+MATCHER_P(DecoderConfigEq, config, "") {
+  return arg.Matches(config);
+}
+
 MATCHER_P(HasTimestamp, timestamp_in_ms, "") {
   return arg.get() && !arg->end_of_stream() &&
          arg->timestamp().InMilliseconds() == timestamp_in_ms;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index c558870..cdc7be4 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1529,7 +1529,7 @@
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
 
-  TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
+  TRACE_EVENT0("media", "WebMediaPlayerImpl::OnVideoNaturalSizeChange");
 
   // The input |size| is from the decoded video frame, which is the original
   // natural size and need to be rotated accordingly.
@@ -1577,6 +1577,28 @@
   }
 }
 
+void WebMediaPlayerImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
+
+  pipeline_metadata_.audio_decoder_config = config;
+
+  if (observer_)
+    observer_->OnMetadataChanged(pipeline_metadata_);
+}
+
+void WebMediaPlayerImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+  DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
+
+  // TODO(chcunningham): Observe changes to video codec profile to signal
+  // beginning of a new Media Capabilities playback report.
+  pipeline_metadata_.video_decoder_config = config;
+
+  if (observer_)
+    observer_->OnMetadataChanged(pipeline_metadata_);
+}
+
 void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
   UpdateBackgroundVideoOptimizationState();
 }
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index d16807c..58d9ff31 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -283,6 +283,8 @@
   void OnAddTextTrack(const TextTrackConfig& config,
                       const AddTextTrackDoneCB& done_cb) override;
   void OnWaitingForDecryptionKey() override;
+  void OnAudioConfigChange(const AudioDecoderConfig& config) override;
+  void OnVideoConfigChange(const VideoDecoderConfig& config) override;
   void OnVideoNaturalSizeChange(const gfx::Size& size) override;
   void OnVideoOpacityChange(bool opaque) override;
   void OnVideoAverageKeyframeDistanceUpdate() override;
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 197c287..ce68dc6 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/json/json_reader.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "media/base/cdm_callback_promise.h"
@@ -23,6 +24,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
 #include "media/base/decryptor.h"
+#include "media/base/media_switches.h"
 #include "media/base/mock_filters.h"
 #include "media/cdm/api/content_decryption_module.h"
 #include "media/cdm/cdm_adapter.h"
@@ -260,6 +262,12 @@
     } else if (GetParam() == "CdmAdapter") {
       CdmConfig cdm_config;  // default settings of false are sufficient.
 
+      // Enable use of External Clear Key CDM.
+      scoped_feature_list_.InitWithFeatures(
+          {media::kExternalClearKeyForTesting,
+           media::kSupportExperimentalCdmInterface},
+          {});
+
       helper_.reset(new ExternalClearKeyTestHelper());
       std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator());
       CdmAdapter::Create(
@@ -476,6 +484,7 @@
   std::unique_ptr<ExternalClearKeyTestHelper> helper_;
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
   // Constants for testing.
   const std::vector<uint8_t> original_data_;
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
index 9f2e9f1a..24d8b3f 100644
--- a/media/cdm/cdm_adapter_unittest.cc
+++ b/media/cdm/cdm_adapter_unittest.cc
@@ -11,10 +11,12 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "media/base/cdm_callback_promise.h"
 #include "media/base/cdm_key_information.h"
 #include "media/base/content_decryption_module.h"
+#include "media/base/media_switches.h"
 #include "media/base/mock_filters.h"
 #include "media/cdm/cdm_file_io.h"
 #include "media/cdm/external_clear_key_test_helper.h"
@@ -88,6 +90,14 @@
   ~CdmAdapterTest() override {}
 
  protected:
+  void SetUp() override {
+    // Enable use of External Clear Key CDM.
+    scoped_feature_list_.InitWithFeatures(
+        {media::kExternalClearKeyForTesting,
+         media::kSupportExperimentalCdmInterface},
+        {});
+  }
+
   // Initializes the adapter. |expected_result| tests that the call succeeds
   // or generates an error.
   void InitializeAndExpect(base::FilePath library_path,
@@ -243,6 +253,7 @@
   std::string session_id_;
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(CdmAdapterTest);
 };
diff --git a/media/cdm/cdm_file_adapter.cc b/media/cdm/cdm_file_adapter.cc
index 2927ae4..d3f97f1 100644
--- a/media/cdm/cdm_file_adapter.cc
+++ b/media/cdm/cdm_file_adapter.cc
@@ -29,7 +29,7 @@
 
 }  // namespace
 
-CdmFileAdapter::CdmFileAdapter(cdm::ContentDecryptionModule_8::Host* host) {
+CdmFileAdapter::CdmFileAdapter(cdm::ContentDecryptionModule_9::Host* host) {
   file_io_ = host->CreateFileIO(this);
 }
 
diff --git a/media/cdm/cdm_file_adapter.h b/media/cdm/cdm_file_adapter.h
index f02324a..dbdfaa7b 100644
--- a/media/cdm/cdm_file_adapter.h
+++ b/media/cdm/cdm_file_adapter.h
@@ -29,7 +29,7 @@
       base::OnceCallback<void(bool success, const std::vector<uint8_t>& data)>;
   using WriteCB = base::OnceCallback<void(bool success)>;
 
-  explicit CdmFileAdapter(cdm::ContentDecryptionModule_8::Host* host);
+  explicit CdmFileAdapter(cdm::ContentDecryptionModule_9::Host* host);
   ~CdmFileAdapter() override;
 
   // Open the file with |name|. |open_cb| will be called when the file is
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index cca58bd..f68412b 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -125,26 +125,24 @@
   return message;
 }
 
-static cdm::Error ConvertException(
+static cdm::Exception ConvertException(
     media::CdmPromise::Exception exception_code) {
   switch (exception_code) {
     case media::CdmPromise::NOT_SUPPORTED_ERROR:
-      return cdm::kNotSupportedError;
+      return cdm::Exception::kExceptionNotSupportedError;
     case media::CdmPromise::INVALID_STATE_ERROR:
-      return cdm::kInvalidStateError;
+      return cdm::Exception::kExceptionInvalidStateError;
     case media::CdmPromise::INVALID_ACCESS_ERROR:
-      return cdm::kInvalidAccessError;
+      return cdm::Exception::kExceptionTypeError;
     case media::CdmPromise::QUOTA_EXCEEDED_ERROR:
-      return cdm::kQuotaExceededError;
+      return cdm::Exception::kExceptionQuotaExceededError;
     case media::CdmPromise::UNKNOWN_ERROR:
-      return cdm::kUnknownError;
     case media::CdmPromise::CLIENT_ERROR:
-      return cdm::kClientError;
     case media::CdmPromise::OUTPUT_ERROR:
-      return cdm::kOutputError;
+      break;
   }
   NOTREACHED();
-  return cdm::kUnknownError;
+  return cdm::Exception::kExceptionNotSupportedError;
 }
 
 static media::CdmSessionType ConvertSessionType(cdm::SessionType session_type) {
@@ -351,6 +349,13 @@
   allow_persistent_state_ = allow_persistent_state;
 }
 
+void ClearKeyCdm::GetStatusForPolicy(uint32_t promise_id,
+                                     const cdm::Policy& policy) {
+  NOTREACHED() << "GetStatusForPolicy() called unexpectedly.";
+  OnPromiseFailed(promise_id, CdmPromise::INVALID_STATE_ERROR, 0,
+                  "GetStatusForPolicy() called unexpectedly.");
+}
+
 void ClearKeyCdm::CreateSessionAndGenerateRequest(
     uint32_t promise_id,
     cdm::SessionType session_type,
@@ -508,7 +513,7 @@
 
   host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(),
                           cdm::kLicenseRenewal, renewal_message.data(),
-                          renewal_message.length(), nullptr, 0);
+                          renewal_message.length());
 
   ScheduleNextRenewal();
 }
@@ -786,15 +791,19 @@
   OnUnitTestComplete(true);
 };
 
+void ClearKeyCdm::OnStorageId(const uint8_t* storage_id,
+                              uint32_t storage_id_size) {
+  NOTREACHED() << "OnStorageId() called unexpectedly.";
+}
+
 void ClearKeyCdm::OnSessionMessage(const std::string& session_id,
                                    CdmMessageType message_type,
                                    const std::vector<uint8_t>& message) {
   DVLOG(1) << __func__ << ": size = " << message.size();
 
-  host_->OnSessionMessage(session_id.data(), session_id.length(),
-                          cdm::kLicenseRequest,
-                          reinterpret_cast<const char*>(message.data()),
-                          message.size(), nullptr, 0);
+  host_->OnSessionMessage(
+      session_id.data(), session_id.length(), cdm::kLicenseRequest,
+      reinterpret_cast<const char*>(message.data()), message.size());
 }
 
 void ClearKeyCdm::OnSessionKeysChange(const std::string& session_id,
@@ -910,7 +919,7 @@
   std::string message = GetUnitTestResultMessage(success);
   host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(),
                           cdm::kLicenseRequest, message.data(),
-                          message.length(), nullptr, 0);
+                          message.length());
 }
 
 void ClearKeyCdm::StartFileIOTest() {
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index 5932ac7..d1d15be 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -43,6 +43,8 @@
   // ClearKeyCdmInterface implementation.
   void Initialize(bool allow_distinctive_identifier,
                   bool allow_persistent_state) override;
+  void GetStatusForPolicy(uint32_t promise_id,
+                          const cdm::Policy& policy) override;
   void CreateSessionAndGenerateRequest(uint32_t promise_id,
                                        cdm::SessionType session_type,
                                        cdm::InitDataType init_data_type,
@@ -85,6 +87,8 @@
   void OnQueryOutputProtectionStatus(cdm::QueryResult result,
                                      uint32_t link_mask,
                                      uint32_t output_protection_mask) override;
+  void OnStorageId(const uint8_t* storage_id,
+                   uint32_t storage_id_size) override;
 
  private:
   // ContentDecryptionModule callbacks.
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
index 5456ac18..699745f 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm_common.h
@@ -10,7 +10,7 @@
 namespace media {
 
 // Aliases for the version of the interfaces that this CDM implements.
-typedef cdm::ContentDecryptionModule_8 ClearKeyCdmInterface;
+typedef cdm::ContentDecryptionModule_9 ClearKeyCdmInterface;
 typedef ClearKeyCdmInterface::Host ClearKeyCdmHost;
 
 }  // namespace media
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index 8ed492a..368469c 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -643,7 +643,7 @@
     pending_buffers_.clear();
 
     if (!config_change_observer_cb_.is_null())
-      config_change_observer_cb_.Run();
+      config_change_observer_cb_.Run(StreamTraits::GetDecoderConfig(stream_));
 
     state_ = STATE_FLUSHING_DECODER;
     if (!reset_cb_.is_null()) {
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index bfbde1d..913da96a 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -42,6 +42,7 @@
   typedef DecoderStreamTraits<StreamType> StreamTraits;
   typedef typename StreamTraits::DecoderType Decoder;
   typedef typename StreamTraits::OutputType Output;
+  typedef typename StreamTraits::DecoderConfigType DecoderConfig;
 
   enum Status {
     OK,  // Everything went as planned.
@@ -110,7 +111,7 @@
   // Allows callers to register for notification of config changes; this is
   // called immediately after receiving the 'kConfigChanged' status from the
   // DemuxerStream, before any action is taken to handle the config change.
-  using ConfigChangeObserverCB = base::Closure;
+  using ConfigChangeObserverCB = base::Callback<void(const DecoderConfig&)>;
   void set_config_change_observer(
       ConfigChangeObserverCB config_change_observer) {
     config_change_observer_cb_ = config_change_observer;
diff --git a/media/filters/pipeline_controller_unittest.cc b/media/filters/pipeline_controller_unittest.cc
index f3cb9e2..4f1c3204 100644
--- a/media/filters/pipeline_controller_unittest.cc
+++ b/media/filters/pipeline_controller_unittest.cc
@@ -136,6 +136,8 @@
                       const AddTextTrackDoneCB& done_cb) override {}
   void OnWaitingForDecryptionKey() override {}
   void OnVideoNaturalSizeChange(const gfx::Size& size) override {}
+  void OnAudioConfigChange(const AudioDecoderConfig& config) {}
+  void OnVideoConfigChange(const VideoDecoderConfig& config) {}
   void OnVideoOpacityChange(bool opaque) override {}
   void OnVideoAverageKeyframeDistanceUpdate() override {}
 
diff --git a/media/mojo/clients/mojo_renderer.cc b/media/mojo/clients/mojo_renderer.cc
index 1331ce3..354f1e3bd 100644
--- a/media/mojo/clients/mojo_renderer.cc
+++ b/media/mojo/clients/mojo_renderer.cc
@@ -15,6 +15,7 @@
 #include "media/base/renderer_client.h"
 #include "media/base/video_renderer_sink.h"
 #include "media/mojo/clients/mojo_demuxer_stream_impl.h"
+#include "media/mojo/common/media_type_converters.h"
 #include "media/renderers/video_overlay_factory.h"
 
 namespace media {
@@ -282,6 +283,18 @@
   client_->OnVideoOpacityChange(opaque);
 }
 
+void MojoRenderer::OnAudioConfigChange(const AudioDecoderConfig& config) {
+  DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  client_->OnAudioConfigChange(config);
+}
+
+void MojoRenderer::OnVideoConfigChange(const VideoDecoderConfig& config) {
+  DVLOG(2) << __func__ << ": " << config.AsHumanReadableString();
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  client_->OnVideoConfigChange(config);
+}
+
 void MojoRenderer::OnStatisticsUpdate(const PipelineStatistics& stats) {
   DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/mojo/clients/mojo_renderer.h b/media/mojo/clients/mojo_renderer.h
index dd7576c..bf5c525 100644
--- a/media/mojo/clients/mojo_renderer.h
+++ b/media/mojo/clients/mojo_renderer.h
@@ -77,6 +77,8 @@
   void OnBufferingStateChange(BufferingState state) override;
   void OnEnded() override;
   void OnError() override;
+  void OnAudioConfigChange(const AudioDecoderConfig& config) override;
+  void OnVideoConfigChange(const VideoDecoderConfig& config) override;
   void OnVideoNaturalSizeChange(const gfx::Size& size) override;
   void OnVideoOpacityChange(bool opaque) override;
   void OnWaitingForDecryptionKey() override;
diff --git a/media/mojo/interfaces/renderer.mojom b/media/mojo/interfaces/renderer.mojom
index 0342f04..8f354d2 100644
--- a/media/mojo/interfaces/renderer.mojom
+++ b/media/mojo/interfaces/renderer.mojom
@@ -72,6 +72,11 @@
   // OnError() will be called before firing the completion callback.
   OnError();
 
+  // Executed whenever DemuxerStream status returns kConfigChange. Initial
+  // configs provided by OnMetadata.
+  OnAudioConfigChange(AudioDecoderConfig config);
+  OnVideoConfigChange(VideoDecoderConfig config);
+
   // Executed for the first video frame and whenever natural size changes.
   OnVideoNaturalSizeChange(gfx.mojom.Size size);
 
diff --git a/media/mojo/services/media_service_unittest.cc b/media/mojo/services/media_service_unittest.cc
index 83d0cc0..05a48f03 100644
--- a/media/mojo/services/media_service_unittest.cc
+++ b/media/mojo/services/media_service_unittest.cc
@@ -58,6 +58,8 @@
   MOCK_METHOD0(OnEnded, void());
   MOCK_METHOD0(OnError, void());
   MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque));
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size& size));
   MOCK_METHOD1(OnStatisticsUpdate,
                void(const media::PipelineStatistics& stats));
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc
index 7f45af51..3ec3a8f 100644
--- a/media/mojo/services/mojo_renderer_service.cc
+++ b/media/mojo/services/mojo_renderer_service.cc
@@ -14,6 +14,7 @@
 #include "media/base/media_url_demuxer.h"
 #include "media/base/renderer.h"
 #include "media/base/video_renderer_sink.h"
+#include "media/mojo/common/media_type_converters.h"
 #include "media/mojo/services/media_resource_shim.h"
 #include "media/mojo/services/mojo_cdm_service_context.h"
 
@@ -186,6 +187,18 @@
   client_->OnWaitingForDecryptionKey();
 }
 
+void MojoRendererService::OnAudioConfigChange(
+    const AudioDecoderConfig& config) {
+  DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
+  client_->OnAudioConfigChange(config);
+}
+
+void MojoRendererService::OnVideoConfigChange(
+    const VideoDecoderConfig& config) {
+  DVLOG(2) << __func__ << "(" << config.AsHumanReadableString() << ")";
+  client_->OnVideoConfigChange(config);
+}
+
 void MojoRendererService::OnVideoNaturalSizeChange(const gfx::Size& size) {
   DVLOG(2) << __func__ << "(" << size.ToString() << ")";
   client_->OnVideoNaturalSizeChange(size);
diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h
index 9d2a83c..569cfc7 100644
--- a/media/mojo/services/mojo_renderer_service.h
+++ b/media/mojo/services/mojo_renderer_service.h
@@ -94,6 +94,8 @@
   void OnStatisticsUpdate(const PipelineStatistics& stats) final;
   void OnBufferingStateChange(BufferingState state) final;
   void OnWaitingForDecryptionKey() final;
+  void OnAudioConfigChange(const AudioDecoderConfig& config) final;
+  void OnVideoConfigChange(const VideoDecoderConfig& config) final;
   void OnVideoNaturalSizeChange(const gfx::Size& size) final;
   void OnVideoOpacityChange(bool opaque) final;
   void OnDurationChange(base::TimeDelta duration) final;
diff --git a/media/remoting/courier_renderer.cc b/media/remoting/courier_renderer.cc
index 6bc07ecc..ba6983c 100644
--- a/media/remoting/courier_renderer.cc
+++ b/media/remoting/courier_renderer.cc
@@ -409,6 +409,12 @@
       VLOG(2) << __func__ << ": Received RPC_RC_ONERROR.";
       OnFatalError(RECEIVER_PIPELINE_ERROR);
       break;
+    case pb::RpcMessage::RPC_RC_ONAUDIOCONFIGCHANGE:
+      OnAudioConfigChange(std::move(message));
+      break;
+    case pb::RpcMessage::RPC_RC_ONVIDEOCONFIGCHANGE:
+      OnVideoConfigChange(std::move(message));
+      break;
     case pb::RpcMessage::RPC_RC_ONVIDEONATURALSIZECHANGE:
       OnVideoNaturalSizeChange(std::move(message));
       break;
@@ -584,6 +590,54 @@
   client_->OnBufferingStateChange(state.value());
 }
 
+void CourierRenderer::OnAudioConfigChange(
+    std::unique_ptr<pb::RpcMessage> message) {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  DCHECK(message);
+  // Shutdown remoting session if receiving malformed RPC message.
+  if (!message->has_rendererclient_onaudioconfigchange_rpc()) {
+    VLOG(1) << __func__ << " missing required RPC message";
+    OnFatalError(RPC_INVALID);
+    return;
+  }
+
+  const auto* audio_config_message =
+      message->mutable_rendererclient_onaudioconfigchange_rpc();
+  const pb::AudioDecoderConfig pb_audio_config =
+      audio_config_message->audio_decoder_config();
+  AudioDecoderConfig out_audio_config;
+  ConvertProtoToAudioDecoderConfig(pb_audio_config, &out_audio_config);
+  DCHECK(out_audio_config.IsValidConfig());
+
+  VLOG(2) << __func__ << ": Received RPC_RC_ONAUDIOCONFIGCHANGE with config:"
+          << out_audio_config.AsHumanReadableString();
+  client_->OnAudioConfigChange(out_audio_config);
+}
+
+void CourierRenderer::OnVideoConfigChange(
+    std::unique_ptr<pb::RpcMessage> message) {
+  DCHECK(media_task_runner_->BelongsToCurrentThread());
+  DCHECK(message);
+  // Shutdown remoting session if receiving malformed RPC message.
+  if (!message->has_rendererclient_onvideoconfigchange_rpc()) {
+    VLOG(1) << __func__ << " missing required RPC message";
+    OnFatalError(RPC_INVALID);
+    return;
+  }
+
+  const auto* video_config_message =
+      message->mutable_rendererclient_onvideoconfigchange_rpc();
+  const pb::VideoDecoderConfig pb_video_config =
+      video_config_message->video_decoder_config();
+  VideoDecoderConfig out_video_config;
+  ConvertProtoToVideoDecoderConfig(pb_video_config, &out_video_config);
+  DCHECK(out_video_config.IsValidConfig());
+
+  VLOG(2) << __func__ << ": Received RPC_RC_ONVIDEOCONFIGCHANGE with config:"
+          << out_video_config.AsHumanReadableString();
+  client_->OnVideoConfigChange(out_video_config);
+}
+
 void CourierRenderer::OnVideoNaturalSizeChange(
     std::unique_ptr<pb::RpcMessage> message) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
diff --git a/media/remoting/courier_renderer.h b/media/remoting/courier_renderer.h
index 55d8d6c..0a03484b 100644
--- a/media/remoting/courier_renderer.h
+++ b/media/remoting/courier_renderer.h
@@ -115,6 +115,8 @@
   void SetCdmCallback(std::unique_ptr<pb::RpcMessage> message);
   void OnTimeUpdate(std::unique_ptr<pb::RpcMessage> message);
   void OnBufferingStateChange(std::unique_ptr<pb::RpcMessage> message);
+  void OnAudioConfigChange(std::unique_ptr<pb::RpcMessage> message);
+  void OnVideoConfigChange(std::unique_ptr<pb::RpcMessage> message);
   void OnVideoNaturalSizeChange(std::unique_ptr<pb::RpcMessage> message);
   void OnVideoOpacityChange(std::unique_ptr<pb::RpcMessage> message);
   void OnStatisticsUpdate(std::unique_ptr<pb::RpcMessage> message);
diff --git a/media/remoting/courier_renderer_unittest.cc b/media/remoting/courier_renderer_unittest.cc
index 1e56062..e60c1ee 100644
--- a/media/remoting/courier_renderer_unittest.cc
+++ b/media/remoting/courier_renderer_unittest.cc
@@ -9,11 +9,13 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "media/base/media_util.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/renderer_client.h"
 #include "media/base/test_helpers.h"
 #include "media/remoting/fake_media_resource.h"
 #include "media/remoting/fake_remoter.h"
+#include "media/remoting/proto_utils.h"
 #include "media/remoting/renderer_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -64,6 +66,12 @@
     ON_CALL(*this, OnBufferingStateChange(_))
         .WillByDefault(
             Invoke(this, &RendererClientImpl::DelegateOnBufferingStateChange));
+    ON_CALL(*this, OnAudioConfigChange(_))
+        .WillByDefault(
+            Invoke(this, &RendererClientImpl::DelegateOnAudioConfigChange));
+    ON_CALL(*this, OnVideoConfigChange(_))
+        .WillByDefault(
+            Invoke(this, &RendererClientImpl::DelegateOnVideoConfigChange));
     ON_CALL(*this, OnVideoNaturalSizeChange(_))
         .WillByDefault(Invoke(
             this, &RendererClientImpl::DelegateOnVideoNaturalSizeChange));
@@ -81,6 +89,8 @@
   void OnEnded() override {}
   MOCK_METHOD1(OnStatisticsUpdate, void(const PipelineStatistics& stats));
   MOCK_METHOD1(OnBufferingStateChange, void(BufferingState state));
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig& config));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig& config));
   void OnWaitingForDecryptionKey() override {}
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size& size));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque));
@@ -90,6 +100,12 @@
     stats_ = stats;
   }
   void DelegateOnBufferingStateChange(BufferingState state) { state_ = state; }
+  void DelegateOnAudioConfigChange(const AudioDecoderConfig& config) {
+    audio_decoder_config_ = config;
+  }
+  void DelegateOnVideoConfigChange(const VideoDecoderConfig& config) {
+    video_decoder_config_ = config;
+  }
   void DelegateOnVideoNaturalSizeChange(const gfx::Size& size) { size_ = size; }
   void DelegateOnVideoOpacityChange(bool opaque) { opaque_ = opaque; }
   void DelegateOnDurationChange(base::TimeDelta duration) {
@@ -109,6 +125,12 @@
   gfx::Size size() const { return size_; }
   bool opaque() const { return opaque_; }
   base::TimeDelta duration() const { return duration_; }
+  VideoDecoderConfig video_decoder_config() const {
+    return video_decoder_config_;
+  }
+  AudioDecoderConfig audio_decoder_config() const {
+    return audio_decoder_config_;
+  }
 
  private:
   PipelineStatus status_ = PIPELINE_OK;
@@ -117,6 +139,8 @@
   bool opaque_ = false;
   base::TimeDelta duration_;
   PipelineStatistics stats_;
+  VideoDecoderConfig video_decoder_config_;
+  AudioDecoderConfig audio_decoder_config_;
 
   DISALLOW_COPY_AND_ASSIGN(RendererClientImpl);
 };
@@ -504,6 +528,54 @@
   RunPendingTasks();
 }
 
+TEST_F(CourierRendererTest, OnAudioConfigChange) {
+  const AudioDecoderConfig kNewAudioConfig(kCodecVorbis, kSampleFormatPlanarF32,
+                                           CHANNEL_LAYOUT_STEREO, 44100,
+                                           EmptyExtraData(), Unencrypted());
+  InitializeRenderer();
+  // Make sure initial audio config does not match the one we intend to send.
+  ASSERT_FALSE(render_client_->audio_decoder_config().Matches(kNewAudioConfig));
+  // Issues RPC_RC_ONVIDEOCONFIGCHANGE RPC message.
+  EXPECT_CALL(*render_client_,
+              OnAudioConfigChange(DecoderConfigEq(kNewAudioConfig)))
+      .Times(1);
+
+  std::unique_ptr<pb::RpcMessage> rpc(new pb::RpcMessage());
+  rpc->set_handle(5);
+  rpc->set_proc(pb::RpcMessage::RPC_RC_ONAUDIOCONFIGCHANGE);
+  auto* audio_config_change_message =
+      rpc->mutable_rendererclient_onaudioconfigchange_rpc();
+  pb::AudioDecoderConfig* proto_audio_config =
+      audio_config_change_message->mutable_audio_decoder_config();
+  ConvertAudioDecoderConfigToProto(kNewAudioConfig, proto_audio_config);
+  OnReceivedRpc(std::move(rpc));
+  RunPendingTasks();
+  ASSERT_TRUE(render_client_->audio_decoder_config().Matches(kNewAudioConfig));
+}
+
+TEST_F(CourierRendererTest, OnVideoConfigChange) {
+  const auto kNewVideoConfig = TestVideoConfig::Normal();
+  InitializeRenderer();
+  // Make sure initial video config does not match the one we intend to send.
+  ASSERT_FALSE(render_client_->video_decoder_config().Matches(kNewVideoConfig));
+  // Issues RPC_RC_ONVIDEOCONFIGCHANGE RPC message.
+  EXPECT_CALL(*render_client_,
+              OnVideoConfigChange(DecoderConfigEq(kNewVideoConfig)))
+      .Times(1);
+
+  std::unique_ptr<pb::RpcMessage> rpc(new pb::RpcMessage());
+  rpc->set_handle(5);
+  rpc->set_proc(pb::RpcMessage::RPC_RC_ONVIDEOCONFIGCHANGE);
+  auto* video_config_change_message =
+      rpc->mutable_rendererclient_onvideoconfigchange_rpc();
+  pb::VideoDecoderConfig* proto_video_config =
+      video_config_change_message->mutable_video_decoder_config();
+  ConvertVideoDecoderConfigToProto(kNewVideoConfig, proto_video_config);
+  OnReceivedRpc(std::move(rpc));
+  RunPendingTasks();
+  ASSERT_TRUE(render_client_->video_decoder_config().Matches(kNewVideoConfig));
+}
+
 TEST_F(CourierRendererTest, OnVideoNaturalSizeChange) {
   InitializeRenderer();
   // Makes sure initial value of video natural size is not set to
diff --git a/media/remoting/receiver.cc b/media/remoting/receiver.cc
index 90dd78b2..ace73dc 100644
--- a/media/remoting/receiver.cc
+++ b/media/remoting/receiver.cc
@@ -9,6 +9,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/renderer.h"
 #include "media/remoting/proto_enum_utils.h"
+#include "media/remoting/proto_utils.h"
 #include "media/remoting/stream_provider.h"
 
 namespace media {
@@ -271,6 +272,30 @@
   rpc_broker_->SendMessageToRemote(std::move(rpc));
 }
 
+void Receiver::OnAudioConfigChange(const AudioDecoderConfig& config) {
+  DVLOG(3) << __func__ << ": Issues RPC_RC_ONAUDIOCONFIGCHANGE message.";
+  std::unique_ptr<pb::RpcMessage> rpc(new pb::RpcMessage());
+  rpc->set_handle(remote_handle_);
+  rpc->set_proc(pb::RpcMessage::RPC_RC_ONAUDIOCONFIGCHANGE);
+  auto* message = rpc->mutable_rendererclient_onaudioconfigchange_rpc();
+  pb::AudioDecoderConfig* proto_audio_config =
+      message->mutable_audio_decoder_config();
+  ConvertAudioDecoderConfigToProto(config, proto_audio_config);
+  rpc_broker_->SendMessageToRemote(std::move(rpc));
+}
+
+void Receiver::OnVideoConfigChange(const VideoDecoderConfig& config) {
+  DVLOG(3) << __func__ << ": Issues RPC_RC_ONVIDEOCONFIGCHANGE message.";
+  std::unique_ptr<pb::RpcMessage> rpc(new pb::RpcMessage());
+  rpc->set_handle(remote_handle_);
+  rpc->set_proc(pb::RpcMessage::RPC_RC_ONVIDEOCONFIGCHANGE);
+  auto* message = rpc->mutable_rendererclient_onvideoconfigchange_rpc();
+  pb::VideoDecoderConfig* proto_video_config =
+      message->mutable_video_decoder_config();
+  ConvertVideoDecoderConfigToProto(config, proto_video_config);
+  rpc_broker_->SendMessageToRemote(std::move(rpc));
+}
+
 void Receiver::OnVideoNaturalSizeChange(const gfx::Size& size) {
   DVLOG(3) << __func__ << ": Issues RPC_RC_ONVIDEONATURALSIZECHANGE message.";
   std::unique_ptr<pb::RpcMessage> rpc(new pb::RpcMessage());
diff --git a/media/remoting/receiver.h b/media/remoting/receiver.h
index 6068ca82..0abd1e5 100644
--- a/media/remoting/receiver.h
+++ b/media/remoting/receiver.h
@@ -36,6 +36,8 @@
   void OnStatisticsUpdate(const PipelineStatistics& stats) override;
   void OnBufferingStateChange(BufferingState state) override;
   void OnWaitingForDecryptionKey() override;
+  void OnAudioConfigChange(const AudioDecoderConfig& config) override;
+  void OnVideoConfigChange(const VideoDecoderConfig& config) override;
   void OnVideoNaturalSizeChange(const gfx::Size& size) override;
   void OnVideoOpacityChange(bool opaque) override;
   void OnDurationChange(base::TimeDelta duration) override;
diff --git a/media/remoting/rpc.proto b/media/remoting/rpc.proto
index aaab7b39..6eb91af 100644
--- a/media/remoting/rpc.proto
+++ b/media/remoting/rpc.proto
@@ -337,6 +337,14 @@
   optional State state = 1;
 }
 
+message RendererClientOnAudioConfigChange {
+  optional AudioDecoderConfig audio_decoder_config = 1;
+}
+
+message RendererClientOnVideoConfigChange {
+  optional VideoDecoderConfig video_decoder_config = 1;
+}
+
 message DemuxerStreamReadUntil {
   optional int32 callback_handle = 1;
   optional uint32 count = 2;
@@ -473,6 +481,8 @@
     RPC_RC_ONSTATISTICSUPDATE = 2006;
     RPC_RC_ONWAITINGFORDECRYPTIONKEY = 2007;
     RPC_RC_ONDURATIONCHANGE = 2008;
+    RPC_RC_ONAUDIOCONFIGCHANGE = 2009;
+    RPC_RC_ONVIDEOCONFIGCHANGE = 2010;
     // DemuxerStream message
     RPC_DS_INITIALIZE = 3000;
     RPC_DS_READUNTIL = 3001;
@@ -555,9 +565,15 @@
     Size rendererclient_onvideonatualsizechange_rpc = 201;
     // RPC_RC_ONSTATISTICSUPDATE
     PipelineStatistics rendererclient_onstatisticsupdate_rpc = 202;
-    // RPC_RC_ONTIMEUPDATE
+    // RPC_RC_ONBUFFERINGSTATECHANGE
     RendererClientOnBufferingStateChange
         rendererclient_onbufferingstatechange_rpc = 203;
+    // RPC_RC_ONAUDIOCONFIGCHANGE
+    RendererClientOnAudioConfigChange rendererclient_onaudioconfigchange_rpc =
+        204;
+    // RPC_RC_ONVIDEOCONFIGCHANGE
+    RendererClientOnVideoConfigChange rendererclient_onvideoconfigchange_rpc =
+        205;
 
     // RPC_DS_READUNTIL
     DemuxerStreamReadUntil demuxerstream_readuntil_rpc = 300;
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 0d417c40..c1a4531 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -357,6 +357,9 @@
   state_ = kInitializing;
   client_ = client;
 
+  current_decoder_config_ = stream->audio_decoder_config();
+  DCHECK(current_decoder_config_.IsValidConfig());
+
   audio_buffer_stream_ = base::MakeUnique<AudioBufferStream>(
       task_runner_, create_audio_decoders_cb_, media_log_);
 
@@ -612,7 +615,8 @@
                  << " ts:" << buffer->timestamp().InMicroseconds()
                  << " old:" << last_decoded_sample_rate_
                  << " new:" << buffer->sample_rate();
-        OnConfigChange();
+        // Send a bogus config to reset timestamp state.
+        OnConfigChange(AudioDecoderConfig());
       }
       last_decoded_sample_rate_ = buffer->sample_rate();
 
@@ -980,10 +984,19 @@
   state_ = new_state;
 }
 
-void AudioRendererImpl::OnConfigChange() {
+void AudioRendererImpl::OnConfigChange(const AudioDecoderConfig& config) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(expecting_config_changes_);
   buffer_converter_->ResetTimestampState();
+
+  // An invalid config may be supplied by callers who simply want to reset
+  // internal state outside of detecting a new config from the demuxer stream.
+  // RendererClient only cares to know about config changes that differ from
+  // previous configs.
+  if (config.IsValidConfig() && !current_decoder_config_.Matches(config)) {
+    current_decoder_config_ = config;
+    client_->OnAudioConfigChange(config);
+  }
 }
 
 void AudioRendererImpl::SetBufferingState_Locked(
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index e4d6e94d..15d2ffd1 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -29,6 +29,7 @@
 #include "base/power_monitor/power_observer.h"
 #include "base/synchronization/lock.h"
 #include "media/base/audio_decoder.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/audio_renderer.h"
 #include "media/base/audio_renderer_sink.h"
 #include "media/base/decryptor.h"
@@ -186,6 +187,11 @@
   void OnBufferingStateChange(BufferingState state);
   void OnWaitingForDecryptionKey();
 
+  // Generally called by the AudioBufferStream when a config change occurs. May
+  // also be called internally with an empty config to reset config-based state.
+  // Will notify RenderClient when called with a valid config.
+  void OnConfigChange(const AudioDecoderConfig& config);
+
   // Used to initiate the flush operation once all pending reads have
   // completed.
   void DoFlush_Locked();
@@ -193,9 +199,6 @@
   // Called when the |decoder_|.Reset() has completed.
   void ResetDecoderDone();
 
-  // Called by the AudioBufferStream when a config change occurs.
-  void OnConfigChange();
-
   // Updates |buffering_state_| and fires |buffering_state_cb_|.
   void SetBufferingState_Locked(BufferingState buffering_state);
 
@@ -210,6 +213,11 @@
   // Whether or not we expect to handle config changes.
   bool expecting_config_changes_;
 
+  // Stores the last decoder config that was passed to
+  // RendererClient::OnAudioConfigChange. Used to prevent signaling config
+  // to the upper layers when when the new config is the same.
+  AudioDecoderConfig current_decoder_config_;
+
   // The sink (destination) for rendered audio. |sink_| must only be accessed
   // on |task_runner_|. |sink_| must never be called under |lock_| or else we
   // may deadlock between |task_runner_| and the audio callback thread.
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index cb0210d4..ecc7ff3e 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -174,6 +174,8 @@
   }
   MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
   MOCK_METHOD1(OnDurationChange, void(base::TimeDelta));
@@ -183,6 +185,7 @@
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(0);
     EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(0);
+    EXPECT_CALL(*this, OnVideoConfigChange(_)).Times(0);
     renderer_->Initialize(demuxer_stream, nullptr, this, pipeline_status_cb);
   }
 
@@ -385,8 +388,8 @@
     return OutputFrames(buffer_capacity().value - frames_buffered().value);
   }
 
-  void force_config_change() {
-    renderer_->OnConfigChange();
+  void force_config_change(const AudioDecoderConfig& config) {
+    renderer_->OnConfigChange(config);
   }
 
   InputFrames converter_input_frames_left() const {
@@ -514,6 +517,35 @@
   event.RunAndWaitForStatus(PIPELINE_OK);
 }
 
+TEST_F(AudioRendererImplTest, SignalConfigChange) {
+  // Initialize and start playback.
+  Initialize();
+  Preroll();
+  StartTicking();
+  EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
+  WaitForPendingRead();
+
+  // Force config change to simulate detected change from decoder stream. Expect
+  // that RendererClient to be signaled with the new config.
+  const AudioDecoderConfig kValidAudioConfig(
+      kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
+      EmptyExtraData(), Unencrypted());
+  EXPECT_TRUE(kValidAudioConfig.IsValidConfig());
+  EXPECT_CALL(*this, OnAudioConfigChange(DecoderConfigEq(kValidAudioConfig)));
+  force_config_change(kValidAudioConfig);
+
+  // Verify rendering can continue after config change.
+  EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
+  WaitForPendingRead();
+
+  // Force a config change with an invalid dummy config. This is occasionally
+  // done to reset internal state and should not bubble to the RendererClient.
+  EXPECT_CALL(*this, OnAudioConfigChange(_)).Times(0);
+  const AudioDecoderConfig kInvalidConfig;
+  EXPECT_FALSE(kInvalidConfig.IsValidConfig());
+  force_config_change(kInvalidConfig);
+}
+
 TEST_F(AudioRendererImplTest, Preroll) {
   Initialize();
   Preroll();
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index d36e948..a1ede61 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -51,6 +51,12 @@
   void OnWaitingForDecryptionKey() override {
     renderer_->OnWaitingForDecryptionKey();
   }
+  void OnAudioConfigChange(const AudioDecoderConfig& config) override {
+    renderer_->OnAudioConfigChange(config);
+  }
+  void OnVideoConfigChange(const VideoDecoderConfig& config) override {
+    renderer_->OnVideoConfigChange(config);
+  }
   void OnVideoNaturalSizeChange(const gfx::Size& size) override {
     DCHECK(type_ == DemuxerStream::VIDEO);
     renderer_->OnVideoNaturalSizeChange(size);
@@ -994,6 +1000,16 @@
   client_->OnWaitingForDecryptionKey();
 }
 
+void RendererImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  client_->OnAudioConfigChange(config);
+}
+
+void RendererImpl::OnVideoConfigChange(const VideoDecoderConfig& config) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  client_->OnVideoConfigChange(config);
+}
+
 void RendererImpl::OnVideoNaturalSizeChange(const gfx::Size& size) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   client_->OnVideoNaturalSizeChange(size);
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h
index 7e78749..89521c6 100644
--- a/media/renderers/renderer_impl.h
+++ b/media/renderers/renderer_impl.h
@@ -17,12 +17,14 @@
 #include "base/time/clock.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/buffering_state.h"
 #include "media/base/decryptor.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/renderer.h"
+#include "media/base/video_decoder_config.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
@@ -171,8 +173,11 @@
 
   // Callback executed when a runtime error happens.
   void OnError(PipelineStatus error);
+
   void OnWaitingForDecryptionKey();
   void OnVideoNaturalSizeChange(const gfx::Size& size);
+  void OnAudioConfigChange(const AudioDecoderConfig& config);
+  void OnVideoConfigChange(const VideoDecoderConfig& config);
   void OnVideoOpacityChange(bool opaque);
 
   void OnStreamRestartCompleted();
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 5f3ada1d..def6618 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -237,6 +237,8 @@
 
   video_frame_stream_.reset(new VideoFrameStream(
       task_runner_, create_video_decoders_cb_, media_log_));
+  video_frame_stream_->set_config_change_observer(base::Bind(
+      &VideoRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr()));
 
   // Always re-initialize or reset the |gpu_memory_buffer_pool_| in case we are
   // switching between video tracks with incompatible video formats (e.g. 8-bit
@@ -263,6 +265,9 @@
   wall_clock_time_cb_ = wall_clock_time_cb;
   state_ = kInitializing;
 
+  current_decoder_config_ = stream->video_decoder_config();
+  DCHECK(current_decoder_config_.IsValidConfig());
+
   video_frame_stream_->Initialize(
       stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
                          weak_factory_.GetWeakPtr()),
@@ -379,6 +384,18 @@
   client_->OnWaitingForDecryptionKey();
 }
 
+void VideoRendererImpl::OnConfigChange(const VideoDecoderConfig& config) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(config.IsValidConfig());
+
+  // RendererClient only cares to know about config changes that differ from
+  // previous configs.
+  if (!current_decoder_config_.Matches(config)) {
+    current_decoder_config_ = config;
+    client_->OnVideoConfigChange(config);
+  }
+}
+
 void VideoRendererImpl::SetTickClockForTesting(
     std::unique_ptr<base::TickClock> tick_clock) {
   tick_clock_.swap(tick_clock);
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h
index 07e6c9a..2785bed 100644
--- a/media/renderers/video_renderer_impl.h
+++ b/media/renderers/video_renderer_impl.h
@@ -22,6 +22,7 @@
 #include "media/base/media_log.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/video_decoder.h"
+#include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_renderer.h"
 #include "media/base/video_renderer_sink.h"
@@ -106,6 +107,10 @@
   void OnBufferingStateChange(BufferingState state);
   void OnWaitingForDecryptionKey();
 
+  // Called by the VideoFrameStream when a config change occurs. Will notify
+  // RenderClient of the new config.
+  void OnConfigChange(const VideoDecoderConfig& config);
+
   // Callback for |video_frame_stream_| to deliver decoded video frames and
   // report video decoding status. If a frame is available the planes will be
   // copied asynchronously and FrameReady will be called once finished copying.
@@ -210,6 +215,11 @@
   VideoRendererSink* const sink_;
   bool sink_started_;
 
+  // Stores the last decoder config that was passed to
+  // RendererClient::OnVideoConfigChange. Used to prevent signaling config
+  // to the upper layers when when the new config is the same.
+  VideoDecoderConfig current_decoder_config_;
+
   // Used for accessing data members.
   base::Lock lock_;
 
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index 5e680b7..eea5882 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -140,6 +140,7 @@
     if (low_delay)
       demuxer_stream->set_liveness(DemuxerStream::LIVENESS_LIVE);
     EXPECT_CALL(mock_cb_, OnWaitingForDecryptionKey()).Times(0);
+    EXPECT_CALL(mock_cb_, OnAudioConfigChange(_)).Times(0);
     renderer_->Initialize(demuxer_stream, nullptr, &mock_cb_,
                           base::Bind(&WallClockTimeSource::GetWallClockTimes,
                                      base::Unretained(&time_source_)),
@@ -1311,6 +1312,31 @@
   Destroy();
 }
 
+TEST_F(VideoRendererImplTest, VideoConfigChange) {
+  Initialize();
+
+  // Configure demuxer stream to allow config changes.
+  EXPECT_CALL(demuxer_stream_, SupportsConfigChanges())
+      .WillRepeatedly(Return(true));
+
+  // Signal a config change at the next DemuxerStream::Read().
+  EXPECT_CALL(demuxer_stream_, Read(_))
+      .WillOnce(RunCallback<0>(DemuxerStream::kConfigChanged, nullptr));
+
+  // Use LargeEncrypted config (non-default) to ensure its plumbed through to
+  // callback.
+  demuxer_stream_.set_video_decoder_config(TestVideoConfig::LargeEncrypted());
+
+  EXPECT_CALL(mock_cb_, OnVideoConfigChange(
+                            DecoderConfigEq(TestVideoConfig::LargeEncrypted())))
+      .Times(1);
+
+  // Start plyaing to trigger DemuxerStream::Read(), surfacing the config change
+  StartPlayingFrom(0);
+
+  Destroy();
+}
+
 TEST_F(VideoRendererImplTest, NaturalSizeChange) {
   Initialize();
 
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 0b9831e..e2f9225 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1161,7 +1161,11 @@
                          kAppendWholeFile);
   EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(640, 360))).Times(1);
+  const gfx::Size kNewSize(640, 360);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-640x360.webm");
   ASSERT_TRUE(source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
@@ -1278,7 +1282,11 @@
   EXPECT_EQ(PIPELINE_OK,
             StartPipelineWithEncryptedMedia(&source, &encrypted_media));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(640, 360))).Times(1);
+  const gfx::Size kNewSize(640, 360);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-640x360-av_enc-av.webm");
 
@@ -1307,7 +1315,11 @@
   EXPECT_EQ(PIPELINE_OK,
             StartPipelineWithEncryptedMedia(&source, &encrypted_media));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(640, 360))).Times(1);
+  const gfx::Size kNewSize(640, 360);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-640x360-av_enc-av.webm");
 
@@ -1338,7 +1350,11 @@
   EXPECT_EQ(PIPELINE_OK,
             StartPipelineWithEncryptedMedia(&source, &encrypted_media));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(640, 360))).Times(1);
+  const gfx::Size kNewSize(640, 360);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-640x360.webm");
 
@@ -1586,7 +1602,11 @@
   MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
   EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);
+  const gfx::Size kNewSize(1280, 720);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-1280x720-av_frag.mp4");
   ASSERT_TRUE(source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
@@ -1614,7 +1634,11 @@
   EXPECT_EQ(PIPELINE_OK,
             StartPipelineWithEncryptedMedia(&source, &encrypted_media));
 
-  EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);
+  const gfx::Size kNewSize(1280, 720);
+  EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(
+                         &VideoDecoderConfig::natural_size, kNewSize)))
+      .Times(1);
+  EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);
   scoped_refptr<DecoderBuffer> second_file =
       ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
   ASSERT_TRUE(source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 1629a0b..debd138 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -238,6 +238,13 @@
   // media files are provided in advance.
   EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
 
+  // SRC= demuxer does not support config changes.
+  for (auto* stream : demuxer_->GetAllStreams()) {
+    EXPECT_FALSE(stream->SupportsConfigChanges());
+  }
+  EXPECT_CALL(*this, OnAudioConfigChange(_)).Times(0);
+  EXPECT_CALL(*this, OnVideoConfigChange(_)).Times(0);
+
   pipeline_->Start(demuxer_.get(),
                    renderer_factory_->CreateRenderer(prepend_video_decoders_cb,
                                                      prepend_audio_decoders_cb),
@@ -531,6 +538,15 @@
       &PipelineIntegrationTestBase::OnStatusCallback, base::Unretained(this)));
   demuxer_ = source->GetDemuxer();
 
+  // MediaSource demuxer may signal config changes.
+  for (auto* stream : demuxer_->GetAllStreams()) {
+    EXPECT_TRUE(stream->SupportsConfigChanges());
+  }
+  // Config change tests should set more specific expectations about the number
+  // of calls.
+  EXPECT_CALL(*this, OnAudioConfigChange(_)).Times(AnyNumber());
+  EXPECT_CALL(*this, OnVideoConfigChange(_)).Times(AnyNumber());
+
   if (encrypted_media) {
     EXPECT_CALL(*this, DecryptorAttached(true));
 
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index 87f3c277..44e6dbd 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -222,6 +222,8 @@
                     const AddTextTrackDoneCB& done_cb));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
+  MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
+  MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
   MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void());
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 651be873..79a79db5 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -42,7 +42,8 @@
 # in addition to use_openssl_certs or use_nss_certs, in that case byte certs
 # are used internally but OpenSSL or NSS are used for certificate verification.
 # TODO(mattm): crbug.com/671420: Implement and enable this for all platforms.
-use_byte_certs = is_mac || is_android || is_nacl || is_ios || is_win
+use_byte_certs =
+    is_mac || is_android || is_nacl || is_ios || is_win || is_fuchsia
 
 buildflag_header("features") {
   header = "net_features.h"
@@ -1948,6 +1949,14 @@
         "base/platform_mime_util_linux.cc",
       ]
     }
+
+    if (is_fuchsia) {
+      sources += [
+        "base/platform_mime_util_fuchsia.cc",
+        "cert/cert_database_fuchsia.cc",
+        "cert/test_root_certs_fuchsia.cc",
+      ]
+    }
   } else {
     public_deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
   }
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn
index 8ef6f7c..048c35b 100644
--- a/net/android/BUILD.gn
+++ b/net/android/BUILD.gn
@@ -53,6 +53,7 @@
   testonly = true
   java_files = [
     "../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java",
+    "../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java",
     "../test/android/javatests/src/org/chromium/net/test/util/CertTestUtil.java",
     "../test/android/javatests/src/org/chromium/net/test/util/NetworkChangeNotifierTestUtil.java",
     "../test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java",
@@ -62,6 +63,8 @@
     ":net_java",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/android_support_test_runner:runner_java",
     "//third_party/android_tools:android_support_annotations_java",
     "//third_party/junit",
   ]
diff --git a/net/base/platform_mime_util_fuchsia.cc b/net/base/platform_mime_util_fuchsia.cc
new file mode 100644
index 0000000..f3bdc98b
--- /dev/null
+++ b/net/base/platform_mime_util_fuchsia.cc
@@ -0,0 +1,38 @@
+// 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 "net/base/platform_mime_util.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace net {
+
+bool PlatformMimeUtil::GetPlatformMimeTypeFromExtension(
+    const base::FilePath::StringType& ext,
+    std::string* result) const {
+  // TODO(fuchsia): Is there MIME DB on Fuchsia? Do we need it?
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool PlatformMimeUtil::GetPreferredExtensionForMimeType(
+    const std::string& mime_type,
+    base::FilePath::StringType* ext) const {
+  // TODO(fuchsia): Is there MIME DB on Fuchsia? Do we need it?
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void PlatformMimeUtil::GetPlatformExtensionsForMimeType(
+    const std::string& mime_type,
+    std::unordered_set<base::FilePath::StringType>* extensions) const {
+  base::FilePath::StringType ext;
+  if (GetPreferredExtensionForMimeType(mime_type, &ext))
+    extensions->insert(ext);
+}
+
+}  // namespace net
diff --git a/net/cert/cert_database_fuchsia.cc b/net/cert/cert_database_fuchsia.cc
new file mode 100644
index 0000000..e9f884e
--- /dev/null
+++ b/net/cert/cert_database_fuchsia.cc
@@ -0,0 +1,16 @@
+// 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 "net/cert/cert_database.h"
+
+#include "base/observer_list_threadsafe.h"
+
+namespace net {
+
+CertDatabase::CertDatabase()
+    : observer_list_(new base::ObserverListThreadSafe<Observer>) {}
+
+CertDatabase::~CertDatabase() {}
+
+}  // namespace net
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index 38e6bff0..9d952e8a 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -42,6 +42,8 @@
 #elif defined(OS_WIN)
 #include "base/win/windows_version.h"
 #include "net/cert/cert_verify_proc_win.h"
+#elif defined(OS_FUCHSIA)
+#include "net/cert/cert_verify_proc_builtin.h"
 #else
 #error Implement certificate verification.
 #endif
@@ -500,7 +502,7 @@
 }  // namespace
 
 // static
-CertVerifyProc* CertVerifyProc::CreateDefault() {
+scoped_refptr<CertVerifyProc> CertVerifyProc::CreateDefault() {
 #if defined(USE_NSS_CERTS)
   return new CertVerifyProcNSS();
 #elif defined(OS_ANDROID)
@@ -511,6 +513,8 @@
   return new CertVerifyProcMac();
 #elif defined(OS_WIN)
   return new CertVerifyProcWin();
+#elif defined(OS_FUCHSIA)
+  return CreateCertVerifyProcBuiltin();
 #else
 #error Unsupported platform
 #endif
diff --git a/net/cert/cert_verify_proc.h b/net/cert/cert_verify_proc.h
index 33f87ee..6a6e3f3 100644
--- a/net/cert/cert_verify_proc.h
+++ b/net/cert/cert_verify_proc.h
@@ -29,7 +29,7 @@
     : public base::RefCountedThreadSafe<CertVerifyProc> {
  public:
   // Creates and returns the default CertVerifyProc.
-  static CertVerifyProc* CreateDefault();
+  static scoped_refptr<CertVerifyProc> CreateDefault();
 
   // Verifies the certificate against the given hostname as an SSL server
   // certificate. Returns OK if successful or an error code upon failure.
diff --git a/net/cert/cert_verify_proc_blacklist.inc b/net/cert/cert_verify_proc_blacklist.inc
index 7cdb730b..0778a8cb 100644
--- a/net/cert/cert_verify_proc_blacklist.inc
+++ b/net/cert/cert_verify_proc_blacklist.inc
@@ -51,6 +51,10 @@
         {0x45, 0x5b, 0x87, 0xe9, 0x6f, 0x1c, 0xea, 0x2f, 0x8b, 0x6d, 0xae,
          0x08, 0x08, 0xec, 0x24, 0x73, 0x8f, 0xd9, 0x2b, 0x7f, 0xd3, 0x06,
          0x75, 0x71, 0x98, 0xbf, 0x38, 0x9d, 0x75, 0x5c, 0x0b, 0x6c},
+        // b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem
+        {0x4b, 0xb8, 0xf3, 0x5b, 0xa1, 0xe1, 0x26, 0xf8, 0xdd, 0xe1, 0xb0,
+         0xc4, 0x20, 0x62, 0x5e, 0xd8, 0x6d, 0xce, 0x61, 0xa7, 0xbd, 0xda,
+         0xdb, 0xde, 0xa9, 0xab, 0xa5, 0x78, 0xff, 0x13, 0x14, 0x5e},
         // 7abd72a323c9d179c722564f4e27a51dd4afd24006b38a40ce918b94960bcf18.pem
         {0x57, 0x80, 0x94, 0x46, 0xea, 0xf1, 0x14, 0x84, 0x38, 0x54, 0xfe,
          0x63, 0x6e, 0xd9, 0xbc, 0xb5, 0x52, 0xe3, 0xc6, 0x16, 0x66, 0x3b,
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index fdb96b1d..e912a2ac 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -134,6 +134,8 @@
   return CERT_VERIFY_PROC_MAC;
 #elif defined(OS_WIN)
   return CERT_VERIFY_PROC_WIN;
+#elif defined(OS_FUCHSIA)
+  return CERT_VERIFY_PROC_BUILTIN;
 #else
 // Will fail to compile.
 #endif
diff --git a/net/cert/multi_threaded_cert_verifier.cc b/net/cert/multi_threaded_cert_verifier.cc
index 567edc2..ab471e68 100644
--- a/net/cert/multi_threaded_cert_verifier.cc
+++ b/net/cert/multi_threaded_cert_verifier.cc
@@ -341,7 +341,7 @@
 };
 
 MultiThreadedCertVerifier::MultiThreadedCertVerifier(
-    CertVerifyProc* verify_proc)
+    scoped_refptr<CertVerifyProc> verify_proc)
     : requests_(0), inflight_joins_(0), verify_proc_(verify_proc) {}
 
 MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
diff --git a/net/cert/multi_threaded_cert_verifier.h b/net/cert/multi_threaded_cert_verifier.h
index 72ec488a..9787fc88 100644
--- a/net/cert/multi_threaded_cert_verifier.h
+++ b/net/cert/multi_threaded_cert_verifier.h
@@ -31,7 +31,7 @@
 // synchronous CertVerifier implementations on worker threads.
 class NET_EXPORT_PRIVATE MultiThreadedCertVerifier : public CertVerifier {
  public:
-  explicit MultiThreadedCertVerifier(CertVerifyProc* verify_proc);
+  explicit MultiThreadedCertVerifier(scoped_refptr<CertVerifyProc> verify_proc);
 
   // When the verifier is destroyed, all certificate verifications requests are
   // canceled, and their completion callbacks will not be called.
diff --git a/net/cert/test_root_certs.h b/net/cert/test_root_certs.h
index 7b2ab5e1..8a87704e 100644
--- a/net/cert/test_root_certs.h
+++ b/net/cert/test_root_certs.h
@@ -127,7 +127,7 @@
   bool allow_system_trust_;
 #endif
 
-#if defined(OS_WIN) || defined(OS_ANDROID)
+#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
   // True if there are no temporarily trusted root certificates.
   bool empty_;
 #endif
diff --git a/net/cert/test_root_certs_fuchsia.cc b/net/cert/test_root_certs_fuchsia.cc
new file mode 100644
index 0000000..d71647fb
--- /dev/null
+++ b/net/cert/test_root_certs_fuchsia.cc
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/test_root_certs.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "net/cert/x509_certificate.h"
+
+namespace net {
+
+bool TestRootCerts::Add(X509Certificate* certificate) {
+  // TODO(fuchsia): Implement this.
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void TestRootCerts::Clear() {
+  // TODO(fuchsia): Implement this.
+  NOTIMPLEMENTED();
+  empty_ = true;
+}
+
+bool TestRootCerts::IsEmpty() const {
+  return empty_;
+}
+
+TestRootCerts::~TestRootCerts() {}
+
+void TestRootCerts::Init() {
+  empty_ = true;
+}
+
+}  // namespace net
diff --git a/net/data/ssl/blacklist/README.md b/net/data/ssl/blacklist/README.md
index 713d300..5c8da4cb 100644
--- a/net/data/ssl/blacklist/README.md
+++ b/net/data/ssl/blacklist/README.md
@@ -143,6 +143,17 @@
 
   * [83618f932d6947744d5ecca299d4b2820c01483947bd16be814e683f7436be24.pem](83618f932d6947744d5ecca299d4b2820c01483947bd16be814e683f7436be24.pem)
 
+### Superfish
+
+For details, see <https://www.eff.org/deeplinks/2015/02/how-remove-superfish-adware-your-lenovo-computer>
+
+Superfish software with an associated root certificate came preinstalled on
+Lenovo computers. The software used a single root certificate across all
+computers, and the private key was trivially extracted; thus the associated
+public key was blacklisted.
+
+  * [b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem](b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem)
+
 ## Miscellaneous
 
 ### DigiCert
diff --git a/net/data/ssl/blacklist/b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem b/net/data/ssl/blacklist/b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem
new file mode 100644
index 0000000..bc333a0
--- /dev/null
+++ b/net/data/ssl/blacklist/b6fe9151402bad1c06d7e66db67a26aa7356f2e6c644dbcf9f98968ff632e1b7.pem
@@ -0,0 +1,61 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 15203047915477327079 (0xd2fc1387a944dce7)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: O=Superfish, Inc., L=SF, ST=CA, C=US, CN=Superfish, Inc.
+        Validity
+            Not Before: May 12 16:25:26 2014 GMT
+            Not After : May  7 16:25:26 2034 GMT
+        Subject: O=Superfish, Inc., L=SF, ST=CA, C=US, CN=Superfish, Inc.
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:e8:f3:4a:18:76:5f:19:3f:b1:cf:58:e9:7f:43:
+                    07:09:95:80:35:c5:0f:fe:71:31:27:81:99:12:26:
+                    20:a5:df:8f:6a:fc:42:55:39:ee:09:38:89:d9:e0:
+                    36:c4:ac:01:82:5b:d5:39:e6:f9:8f:07:88:df:fe:
+                    ee:f6:a1:14:ce:a9:74:45:d8:fd:f0:17:57:2a:82:
+                    e1:7a:2e:12:93:5a:ac:8a:d7:15:63:d1:b7:9b:55:
+                    80:0f:58:bc:1c:49:ed:20:62:dd:b6:4c:a5:3a:eb:
+                    1c:3d:a0:ff:7a:71:a6:d3:10:78:33:ae:4b:c2:1c:
+                    fd:92:4a:a1:c3:e7:41:a4:2d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                FB:98:B3:53:7F:14:44:2E:E8:EE:D5:09:9A:5E:0E:56:86:A8:35:88
+            X509v3 Authority Key Identifier: 
+                keyid:FB:98:B3:53:7F:14:44:2E:E8:EE:D5:09:9A:5E:0E:56:86:A8:35:88
+                DirName:/O=Superfish, Inc./L=SF/ST=CA/C=US/CN=Superfish, Inc.
+                serial:D2:FC:13:87:A9:44:DC:E7
+
+    Signature Algorithm: sha1WithRSAEncryption
+         a4:7c:a0:ec:0a:4a:c7:70:c4:71:68:f3:3b:22:e2:dc:9c:8d:
+         d0:92:fe:73:7e:72:2b:55:44:9b:1b:b4:42:eb:1f:af:be:ba:
+         e3:93:a3:d4:8b:18:c2:94:f0:b3:a6:bd:65:34:4c:cd:24:f8:
+         19:0b:c5:15:0a:da:f3:57:8b:a9:86:cf:6c:c3:ee:84:2f:85:
+         0b:19:14:17:98:b4:0c:d4:96:8b:e9:1c:cc:95:c9:4e:d0:aa:
+         4b:01:a5:f6:df:49:12:81:6a:be:d5:be:ce:76:7d:4e:ac:8b:
+         88:e3:30:ed:31:84:50:8f:bc:f1:50:2a:5b:4a:a6:5e:7c:0f:
+         71:fa
+-----BEGIN CERTIFICATE-----
+MIIC9TCCAl6gAwIBAgIJANL8E4epRNznMA0GCSqGSIb3DQEBBQUAMFsxGDAWBgNV
+BAoTD1N1cGVyZmlzaCwgSW5jLjELMAkGA1UEBxMCU0YxCzAJBgNVBAgTAkNBMQsw
+CQYDVQQGEwJVUzEYMBYGA1UEAxMPU3VwZXJmaXNoLCBJbmMuMB4XDTE0MDUxMjE2
+MjUyNloXDTM0MDUwNzE2MjUyNlowWzEYMBYGA1UEChMPU3VwZXJmaXNoLCBJbmMu
+MQswCQYDVQQHEwJTRjELMAkGA1UECBMCQ0ExCzAJBgNVBAYTAlVTMRgwFgYDVQQD
+Ew9TdXBlcmZpc2gsIEluYy4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOjz
+Shh2Xxk/sc9Y6X9DBwmVgDXFD/5xMSeBmRImIKXfj2r8QlU57gk4idngNsSsAYJb
+1Tnm+Y8HiN/+7vahFM6pdEXY/fAXVyqC4XouEpNarIrXFWPRt5tVgA9YvBxJ7SBi
+3bZMpTrrHD2g/3pxptMQeDOuS8Ic/ZJKocPnQaQtAgMBAAGjgcAwgb0wDAYDVR0T
+BAUwAwEB/zAdBgNVHQ4EFgQU+5izU38URC7o7tUJml4OVoaoNYgwgY0GA1UdIwSB
+hTCBgoAU+5izU38URC7o7tUJml4OVoaoNYihX6RdMFsxGDAWBgNVBAoTD1N1cGVy
+ZmlzaCwgSW5jLjELMAkGA1UEBxMCU0YxCzAJBgNVBAgTAkNBMQswCQYDVQQGEwJV
+UzEYMBYGA1UEAxMPU3VwZXJmaXNoLCBJbmMuggkA0vwTh6lE3OcwDQYJKoZIhvcN
+AQEFBQADgYEApHyg7ApKx3DEcWjzOyLi3JyN0JL+c35yK1VEmxu0Qusfr76645Oj
+1IsYwpTws6a9ZTRMzST4GQvFFQra81eLqYbPbMPuhC+FCxkUF5i0DNSWi+kczJXJ
+TtCqSwGl9t9JEoFqvtW+znZ9TqyLiOMw7TGEUI+88VAqW0qmXnwPcfo=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index db701568..088fb9b 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -18,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/dns/dns_hosts.h"
@@ -120,7 +121,8 @@
 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
   ConfigParsePosixResult result;
   config->unhandled_options = false;
-#if defined(OS_OPENBSD)
+// TODO(fuchsia): Use res_ninit() when it's implemented on Fuchsia.
+#if defined(OS_OPENBSD) || defined(OS_FUCHSIA)
   // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
   // res_init behaves the same way.
   memset(&_res, 0, sizeof(_res));
diff --git a/net/dns/dns_reloader.cc b/net/dns/dns_reloader.cc
index e3b845dd..322c8a5 100644
--- a/net/dns/dns_reloader.cc
+++ b/net/dns/dns_reloader.cc
@@ -5,7 +5,7 @@
 #include "net/dns/dns_reloader.h"
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
-    !defined(OS_ANDROID)
+    !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
 #include <resolv.h>
 
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 33d951b8..d5ffa424 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -2059,7 +2059,7 @@
   NetworkChangeNotifier::AddConnectionTypeObserver(this);
   NetworkChangeNotifier::AddDNSObserver(this);
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
-    !defined(OS_ANDROID)
+    !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
   EnsureDnsReloaderInit();
 #endif
 
diff --git a/net/dns/host_resolver_proc.cc b/net/dns/host_resolver_proc.cc
index f1253ad..c070c15 100644
--- a/net/dns/host_resolver_proc.cc
+++ b/net/dns/host_resolver_proc.cc
@@ -199,7 +199,7 @@
   hints.ai_socktype = SOCK_STREAM;
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
-    !defined(OS_ANDROID)
+    !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
   DnsReloaderMaybeReload();
 #endif
   int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
diff --git a/net/features.gni b/net/features.gni
index 95c718e..ab189559 100644
--- a/net/features.gni
+++ b/net/features.gni
@@ -16,11 +16,12 @@
   enable_websockets = !is_ios
   disable_ftp_support = is_ios || is_chromecast
 
-  # Enable Kerberos authentication. It is disabled by default on iOS,
-  # Chromecast, at least for now. This feature needs configuration (krb5.conf
-  # and so on). On Chrome OS it is only supported on Active Directory
-  # managed devices.
-  use_kerberos = !is_ios && !is_chromecast
+  # Enable Kerberos authentication. It is disabled by default on iOS, Fuchsia
+  # and Chromecast, at least for now. This feature needs configuration
+  # (krb5.conf and so on). On Chrome OS it is only supported on Active
+  # Directory managed devices.
+  # TODO(fuchsia): Enable kerberos on Fuchsia when it's implemented there.
+  use_kerberos = !is_ios && !is_chromecast && !is_fuchsia
 
   # Do not disable brotli filter by default.
   disable_brotli_filter = false
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 273aa39..115eb836 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -125,7 +125,6 @@
       quic_disable_bidirectional_streams(false),
       quic_force_hol_blocking(false),
       quic_race_cert_verification(false),
-      quic_do_not_fragment(false),
       quic_estimate_initial_rtt(false),
       enable_token_binding(false),
       http_09_on_non_default_ports_enabled(false) {
@@ -201,7 +200,6 @@
           params.quic_allow_server_migration,
           params.quic_force_hol_blocking,
           params.quic_race_cert_verification,
-          params.quic_do_not_fragment,
           params.quic_estimate_initial_rtt,
           params.quic_connection_options,
           params.enable_token_binding),
@@ -353,7 +351,6 @@
                    params_.quic_migrate_sessions_early);
   dict->SetBoolean("allow_server_migration",
                    params_.quic_allow_server_migration);
-  dict->SetBoolean("do_not_fragment", params_.quic_do_not_fragment);
   dict->SetBoolean("estimate_initial_rtt", params_.quic_estimate_initial_rtt);
   dict->SetBoolean("force_hol_blocking", params_.quic_force_hol_blocking);
   dict->SetBoolean("server_push_cancellation",
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 1b118c9..a90ffc6a 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -156,8 +156,6 @@
     bool quic_force_hol_blocking;
     // If true, race cert verification with host resolution.
     bool quic_race_cert_verification;
-    // If true, configure QUIC sockets to not fragment packets.
-    bool quic_do_not_fragment;
     // If true, estimate the initial RTT for QUIC connections based on network.
     bool quic_estimate_initial_rtt;
 
diff --git a/net/log/file_net_log_observer.h b/net/log/file_net_log_observer.h
index fc1fd8a..747b76a2 100644
--- a/net/log/file_net_log_observer.h
+++ b/net/log/file_net_log_observer.h
@@ -83,7 +83,9 @@
   // Stops observing net_log() and closes the output file(s). Must be called
   // after StartObserving. Should be called before destruction of the
   // FileNetLogObserver and the NetLog, or the NetLog files will be deleted when
-  // the observer is destroyed.
+  // the observer is destroyed. Note that it is OK to destroy |this| immediately
+  // after calling StopObserving() - the callback will still be called once the
+  // file writing has completed.
   //
   // |polled_data| is an optional argument used to add additional network stack
   // state to the log.
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index 00787a41..e65830d 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -670,7 +670,6 @@
     bool allow_server_migration,
     bool force_hol_blocking,
     bool race_cert_verification,
-    bool do_not_fragment,
     bool estimate_initial_rtt,
     const QuicTagVector& connection_options,
     bool enable_token_binding)
@@ -713,7 +712,6 @@
       allow_server_migration_(allow_server_migration),
       force_hol_blocking_(force_hol_blocking),
       race_cert_verification_(race_cert_verification),
-      do_not_fragment_(do_not_fragment),
       estimate_initial_rtt(estimate_initial_rtt),
       check_persisted_supports_quic_(true),
       num_push_streams_created_(0),
@@ -1433,13 +1431,11 @@
     return rv;
   }
 
-  if (do_not_fragment_) {
-    rv = socket->SetDoNotFragment();
-    // SetDoNotFragment is not implemented on all platforms, so ignore errors.
-    if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
-      HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
-      return rv;
-    }
+  rv = socket->SetDoNotFragment();
+  // SetDoNotFragment is not implemented on all platforms, so ignore errors.
+  if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
+    HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
+    return rv;
   }
 
   // Set a buffer large enough to contain the initial CWND's worth of packet
diff --git a/net/quic/chromium/quic_stream_factory.h b/net/quic/chromium/quic_stream_factory.h
index 81b7841..cdd1f996f 100644
--- a/net/quic/chromium/quic_stream_factory.h
+++ b/net/quic/chromium/quic_stream_factory.h
@@ -214,7 +214,6 @@
       bool allow_server_migration,
       bool force_hol_blocking,
       bool race_cert_verification,
-      bool do_not_fragment,
       bool estimate_initial_rtt,
       const QuicTagVector& connection_options,
       bool enable_token_binding);
@@ -555,9 +554,6 @@
   // Set if cert verification is to be raced with host resolution.
   bool race_cert_verification_;
 
-  // If set, configure QUIC sockets to not fragment packets.
-  bool do_not_fragment_;
-
   // If true, estimate the initial RTT based on network type.
   bool estimate_initial_rtt;
 
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc
index d9f1d77..8a9c8c9 100644
--- a/net/quic/chromium/quic_stream_factory_test.cc
+++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -223,7 +223,7 @@
         packet_reader_yield_after_duration_milliseconds_,
         migrate_sessions_on_network_change_, migrate_sessions_early_,
         allow_server_migration_, force_hol_blocking_, race_cert_verification_,
-        /*do_not_fragment*/ true, estimate_initial_rtt_, QuicTagVector(),
+        estimate_initial_rtt_, QuicTagVector(),
         /*enable_token_binding*/ false));
     factory_->set_require_confirmation(false);
   }
diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc
index ecd9adf..86927c8 100644
--- a/net/socket/unix_domain_server_socket_posix.cc
+++ b/net/socket/unix_domain_server_socket_posix.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/base/sockaddr_storage.h"
 #include "net/socket/socket_posix.h"
@@ -47,7 +48,7 @@
 // static
 bool UnixDomainServerSocket::GetPeerCredentials(SocketDescriptor socket,
                                                 Credentials* credentials) {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
   struct ucred user_cred;
   socklen_t len = sizeof(user_cred);
   if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &user_cred, &len) < 0)
diff --git a/net/socket/unix_domain_server_socket_posix.h b/net/socket/unix_domain_server_socket_posix.h
index 27116ee..e5a81d31 100644
--- a/net/socket/unix_domain_server_socket_posix.h
+++ b/net/socket/unix_domain_server_socket_posix.h
@@ -13,6 +13,8 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "build/build_config.h"
+
 #include "net/base/net_export.h"
 #include "net/socket/server_socket.h"
 #include "net/socket/socket_descriptor.h"
@@ -27,8 +29,8 @@
  public:
   // Credentials of a peer process connected to the socket.
   struct NET_EXPORT Credentials {
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-    // Linux/Android API provides more information about the connected peer
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+    // Linux and Fuchsia provide more information about the connected peer
     // than Windows/OS X. It's useful for permission-based authorization on
     // Android.
     pid_t process_id;
diff --git a/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java
new file mode 100644
index 0000000..2288f27
--- /dev/null
+++ b/net/test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerRule.java
@@ -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.
+
+package org.chromium.net.test;
+
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+/**
+ * Junit4 rule for starting embedded test server before a test starts, and shutting it down when it
+ * finishes.
+ */
+public class EmbeddedTestServerRule extends TestWatcher {
+    EmbeddedTestServer mServer = new EmbeddedTestServer();
+
+    @Override
+    protected void starting(Description description) {
+        try {
+            EmbeddedTestServer.initializeAndStartServer(
+                    mServer, InstrumentationRegistry.getContext());
+        } catch (InterruptedException e) {
+            throw new EmbeddedTestServer.EmbeddedTestServerFailure("Test server didn't start");
+        }
+        super.starting(description);
+    }
+
+    @Override
+    protected void finished(Description description) {
+        super.finished(description);
+        mServer.stopAndDestroyServer();
+    }
+
+    /**
+     * Get the test server.
+     *
+     * @return the test server.
+     */
+    public EmbeddedTestServer getServer() {
+        return mServer;
+    }
+}
diff --git a/remoting/android/java/AndroidManifest.xml.jinja2 b/remoting/android/java/AndroidManifest.xml.jinja2
index 073cd33..01cb776 100644
--- a/remoting/android/java/AndroidManifest.xml.jinja2
+++ b/remoting/android/java/AndroidManifest.xml.jinja2
@@ -2,7 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="{{ APK_PACKAGE_NAME }}">
     <uses-sdk android:minSdkVersion="14"
-            android:targetSdkVersion="24"/>
+            android:targetSdkVersion="26"/>
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />
diff --git a/remoting/ios/app/BUILD.gn b/remoting/ios/app/BUILD.gn
index 6b442a6..23b5da4 100644
--- a/remoting/ios/app/BUILD.gn
+++ b/remoting/ios/app/BUILD.gn
@@ -48,6 +48,8 @@
     "remoting_view_controller.mm",
     "session_reconnect_view.h",
     "session_reconnect_view.mm",
+    "side_menu_items.h",
+    "side_menu_items.mm",
   ]
 
   deps = [
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.mm b/remoting/ios/app/settings/remoting_settings_view_controller.mm
index 4674eeab..45e71b77 100644
--- a/remoting/ios/app/settings/remoting_settings_view_controller.mm
+++ b/remoting/ios/app/settings/remoting_settings_view_controller.mm
@@ -87,6 +87,10 @@
   [self loadContent];
 }
 
+- (UIStatusBarStyle)preferredStatusBarStyle {
+  return UIStatusBarStyleLightContent;
+}
+
 #pragma mark - UICollectionViewDataSource
 
 - (NSInteger)numberOfSectionsInCollectionView:
diff --git a/remoting/ios/app/side_menu_items.h b/remoting/ios/app/side_menu_items.h
new file mode 100644
index 0000000..fcd67c7
--- /dev/null
+++ b/remoting/ios/app/side_menu_items.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_IOS_APP_SIDE_MENU_ITEMS_H_
+#define REMOTING_IOS_APP_SIDE_MENU_ITEMS_H_
+
+#import <UIKit/UIKit.h>
+
+typedef void (^SideMenuItemAction)(void);
+
+// Represents an item on the side menu.
+@interface SideMenuItem : NSObject
+
+@property(nonatomic, readonly) NSString* title;
+@property(nonatomic, readonly) UIImage* icon;
+@property(nonatomic, readonly) SideMenuItemAction action;
+
+@end
+
+// Class that provides the list of SideMenuItems to be shown on the side menu.
+@interface SideMenuItemsProvider : NSObject
+
+// Each item is located by sideMenuItems[indexPath.section][indexPath.item]
+@property(nonatomic, readonly, class)
+    NSArray<NSArray<SideMenuItem*>*>* sideMenuItems;
+
+@end
+
+#endif  // REMOTING_IOS_APP_SIDE_MENU_ITEMS_H_
diff --git a/remoting/ios/app/side_menu_items.mm b/remoting/ios/app/side_menu_items.mm
new file mode 100644
index 0000000..4bf4057
--- /dev/null
+++ b/remoting/ios/app/side_menu_items.mm
@@ -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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/ios/app/side_menu_items.h"
+
+#import "remoting/ios/app/app_delegate.h"
+
+static NSString* const kFeedbackContext = @"SideMenuFeedbackContext";
+
+#pragma mark - SideMenuItem
+
+@interface SideMenuItem ()
+
+- (instancetype)initWithTitle:(NSString*)title
+                         icon:(UIImage*)icon
+                       action:(SideMenuItemAction)action;
+
+@end
+
+@implementation SideMenuItem
+
+@synthesize title = _title;
+@synthesize icon = _icon;
+@synthesize action = _action;
+
+- (instancetype)initWithTitle:(NSString*)title
+                         icon:(UIImage*)icon
+                       action:(SideMenuItemAction)action {
+  _title = title;
+  _icon = icon;
+  _action = action;
+  return self;
+}
+
+@end
+
+#pragma mark - SideMenuItemsProvider
+
+@implementation SideMenuItemsProvider
+
++ (NSArray<NSArray<SideMenuItem*>*>*)sideMenuItems {
+  static NSArray<NSArray<SideMenuItem*>*>* items = nil;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    items = @[ @[
+      // TODO(yuweih): Add icons when crbug.com/734054 is fixed.
+      [[SideMenuItem alloc]
+          initWithTitle:@"Send Feedback"
+                   icon:nil
+                 action:^{
+                   [AppDelegate.instance
+                       presentFeedbackFlowWithContext:kFeedbackContext];
+                 }],
+      [[SideMenuItem alloc] initWithTitle:@"Help"
+                                     icon:nil
+                                   action:^{
+                                     NSLog(@"Tapped help");
+                                   }],
+    ] ];
+  });
+  return items;
+}
+
+@end
diff --git a/remoting/ios/client_gestures.mm b/remoting/ios/client_gestures.mm
index 00e5900c..0dbb9dc 100644
--- a/remoting/ios/client_gestures.mm
+++ b/remoting/ios/client_gestures.mm
@@ -30,7 +30,11 @@
   UIPanGestureRecognizer* _panRecognizer;
   UIPanGestureRecognizer* _flingRecognizer;
   UIPanGestureRecognizer* _scrollRecognizer;
-  UIPanGestureRecognizer* _threeFingerPanRecognizer;
+
+  // TODO(yuweih): Commented out because this makes two-finger gestures not
+  // quite responsive. Clean these up if it's really unnecessary.
+  //  UIPanGestureRecognizer* _threeFingerPanRecognizer;
+
   UIPinchGestureRecognizer* _pinchRecognizer;
   UITapGestureRecognizer* _singleTapRecognizer;
   UITapGestureRecognizer* _twoFingerTapRecognizer;
@@ -79,13 +83,13 @@
   _scrollRecognizer.delegate = self;
   [view addGestureRecognizer:_scrollRecognizer];
 
-  _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
-      initWithTarget:self
-              action:@selector(threeFingerPanGestureTriggered:)];
-  _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
-  _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
-  _threeFingerPanRecognizer.delegate = self;
-  [view addGestureRecognizer:_threeFingerPanRecognizer];
+  //  _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
+  //      initWithTarget:self
+  //              action:@selector(threeFingerPanGestureTriggered:)];
+  //  _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
+  //  _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
+  //  _threeFingerPanRecognizer.delegate = self;
+  //  [view addGestureRecognizer:_threeFingerPanRecognizer];
 
   _pinchRecognizer = [[UIPinchGestureRecognizer alloc]
       initWithTarget:self
@@ -117,10 +121,11 @@
   [_twoFingerTapRecognizer
       requireGestureRecognizerToFail:_threeFingerTapRecognizer];
   [_pinchRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
-  [_pinchRecognizer requireGestureRecognizerToFail:_threeFingerPanRecognizer];
+  //  [_pinchRecognizer
+  //  requireGestureRecognizerToFail:_threeFingerPanRecognizer];
   [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
-  [_threeFingerPanRecognizer
-      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
+  //  [_threeFingerPanRecognizer
+  //      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
   [_panRecognizer requireGestureRecognizerToFail:_scrollRecognizer];
 
   return self;
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 7bdaf43..1b55549 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -182,7 +182,10 @@
     "src/lpc_policy_test.cc",
     "src/named_pipe_policy_test.cc",
     "src/policy_target_test.cc",
-    "src/process_mitigations_test.cc",
+    "src/process_mitigations_extensionpoints_unittest.cc",
+    "src/process_mitigations_imageload_unittest.cc",
+    "src/process_mitigations_unittest.cc",
+    "src/process_mitigations_win32k_unittest.cc",
     "src/process_policy_test.cc",
     "src/registry_policy_test.cc",
     "src/restricted_token_test.cc",
@@ -228,14 +231,14 @@
 loadable_module("sbox_integration_test_hook_dll") {
   sources = [
     "tests/integration_tests/hooking_dll.cc",
-    "tests/integration_tests/integration_tests_common.h",
+    "tests/integration_tests/hooking_dll.h",
   ]
 }
 
 executable("sbox_integration_test_win_proc") {
   sources = [
     "tests/integration_tests/hooking_win_proc.cc",
-    "tests/integration_tests/integration_tests_common.h",
+    "tests/integration_tests/hooking_win_proc.h",
   ]
 
   configs -= [ "//build/config/win:console" ]
diff --git a/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc b/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc
new file mode 100644
index 0000000..461400d5
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc
@@ -0,0 +1,521 @@
+// 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 "sandbox/win/src/process_mitigations.h"
+
+#include <windows.h>
+
+#include <psapi.h>
+
+#include "base/scoped_native_library.h"
+#include "base/win/registry.h"
+#include "base/win/startup_information.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/integration_tests/hooking_dll.h"
+#include "sandbox/win/tests/integration_tests/hooking_win_proc.h"
+#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Internal Defines & Functions
+//------------------------------------------------------------------------------
+
+// hooking_dll defines
+using WasHookCalledFunction = decltype(&hooking_dll::WasHookCalled);
+using SetHookFunction = decltype(&hooking_dll::SetHook);
+constexpr char g_hook_handler_func[] = "HookProc";
+constexpr char g_was_hook_called_func[] = "WasHookCalled";
+constexpr char g_set_hook_func[] = "SetHook";
+
+// System mutex to prevent conflicting tests from running at the same time.
+const wchar_t g_extension_point_test_mutex[] = L"ChromeExtensionTestMutex";
+
+//------------------------------------------------------------------------------
+// ExtensionPoint test helper function.
+//
+// Spawn Windows process (with or without mitigation enabled).
+//------------------------------------------------------------------------------
+bool SpawnWinProc(PROCESS_INFORMATION* pi, bool success_test, HANDLE* event) {
+  base::win::StartupInformation startup_info;
+  DWORD creation_flags = 0;
+
+  if (!success_test) {
+    DWORD64 flags =
+        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
+    // This test only runs on >= Win8, so don't have to handle
+    // illegal 64-bit flags on 32-bit <= Win7.
+    size_t flags_size = sizeof(flags);
+
+    if (!startup_info.InitializeProcThreadAttributeList(1) ||
+        !startup_info.UpdateProcThreadAttribute(
+            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &flags, flags_size)) {
+      ADD_FAILURE();
+      return false;
+    }
+    creation_flags = EXTENDED_STARTUPINFO_PRESENT;
+  }
+
+  // Command line must be writable.
+  base::string16 cmd_writeable(hooking_win_proc::g_winproc_file);
+
+  if (!::CreateProcessW(NULL, &cmd_writeable[0], NULL, NULL, FALSE,
+                        creation_flags, NULL, NULL, startup_info.startup_info(),
+                        pi)) {
+    ADD_FAILURE();
+    return false;
+  }
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(*event, sandbox::SboxTestEventTimeout()));
+
+  return true;
+}
+
+//------------------------------------------------------------------------------
+// ExtensionPoint test helper function.
+//
+// 1. Spawn a Windows process (with or without mitigation enabled).
+// 2. Load the hook Dll locally.
+// 3. Create a global named event for the hook to trigger.
+// 4. Start the hook (for the specific WinProc or globally).
+// 5. Send a keystroke event.
+// 6. Ask the hook Dll if it received a hook callback.
+// 7. Cleanup the hooking.
+// 8. Signal the Windows process to shutdown.
+//
+// Do NOT use any ASSERTs in this function.  Cleanup required.
+//------------------------------------------------------------------------------
+void TestWin8ExtensionPointHookWrapper(bool is_success_test, bool global_hook) {
+  // Set up a couple global events that this test will use.
+  HANDLE winproc_event =
+      ::CreateEventW(NULL, FALSE, FALSE, hooking_win_proc::g_winproc_event);
+  if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
+    ADD_FAILURE();
+    return;
+  }
+  base::win::ScopedHandle scoped_winproc_event(winproc_event);
+
+  HANDLE hook_event =
+      ::CreateEventW(NULL, FALSE, FALSE, hooking_dll::g_hook_event);
+  if (hook_event == NULL || hook_event == INVALID_HANDLE_VALUE) {
+    ADD_FAILURE();
+    return;
+  }
+  base::win::ScopedHandle scoped_hook_event(hook_event);
+
+  // 1. Spawn WinProc.
+  PROCESS_INFORMATION proc_info = {};
+  if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
+    return;
+
+  // From this point on, no return on failure.  Cleanup required.
+  bool all_good = true;
+
+  // 2. Load the hook DLL.
+  base::FilePath hook_dll_path(hooking_dll::g_hook_dll_file);
+  base::ScopedNativeLibrary dll(hook_dll_path);
+  EXPECT_TRUE(dll.is_valid());
+
+  HOOKPROC hook_proc =
+      reinterpret_cast<HOOKPROC>(dll.GetFunctionPointer(g_hook_handler_func));
+  WasHookCalledFunction was_hook_called =
+      reinterpret_cast<WasHookCalledFunction>(
+          dll.GetFunctionPointer(g_was_hook_called_func));
+  SetHookFunction set_hook = reinterpret_cast<SetHookFunction>(
+      dll.GetFunctionPointer(g_set_hook_func));
+  if (!hook_proc || !was_hook_called || !set_hook) {
+    ADD_FAILURE();
+    all_good = false;
+  }
+
+  // 3. Try installing the hook (either on a remote target thread,
+  //    or globally).
+  HHOOK hook = nullptr;
+  if (all_good) {
+    DWORD target = 0;
+    if (!global_hook)
+      target = proc_info.dwThreadId;
+    hook = ::SetWindowsHookExW(WH_KEYBOARD, hook_proc, dll.get(), target);
+    if (!hook) {
+      ADD_FAILURE();
+      all_good = false;
+    } else
+      // Pass the hook DLL the hook handle.
+      set_hook(hook);
+  }
+
+  // 4. Inject a keyboard event.
+  if (all_good) {
+    // Note: that PostThreadMessage and SendMessage APIs will not deliver
+    // a keystroke in such a way that triggers a "legitimate" hook.
+    // Have to use targetless SendInput or keybd_event.  The latter is
+    // less code and easier to work with.
+    keybd_event(VkKeyScan(L'A'), 0, 0, 0);
+    keybd_event(VkKeyScan(L'A'), 0, KEYEVENTF_KEYUP, 0);
+    // Give it a chance to hit the hook handler...
+    ::WaitForSingleObject(hook_event, sandbox::SboxTestEventTimeout());
+
+    // 5. Did the hook get hit?  Was it expected to?
+    if (global_hook)
+      EXPECT_EQ((is_success_test ? true : false), was_hook_called());
+    else
+      // ***IMPORTANT: when targeting a specific thread id, the
+      // PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE
+      // mitigation does NOT disable the hook API.  It ONLY
+      // stops global hooks from running in a process.  Hence,
+      // the hook will hit (TRUE) even in the "failure"
+      // case for a non-global/targeted hook.
+      EXPECT_EQ((is_success_test ? true : true), was_hook_called());
+  }
+
+  // 6. Disable hook.
+  if (hook)
+    EXPECT_TRUE(::UnhookWindowsHookEx(hook));
+
+  // 7. Trigger shutdown of WinProc.
+  if (proc_info.hProcess) {
+    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
+      // Note: The combination/perfect-storm of a Global Hook, in a
+      // WinProc that has the EXTENSION_POINT_DISABLE mitigation ON, and the
+      // use of the SendInput or keybd_event API to inject a keystroke,
+      // results in the target becoming unresponsive.  If any one of these
+      // states are changed, the problem does not occur.  This means the WM_QUIT
+      // message is not handled and the call to WaitForSingleObject times out.
+      // Therefore not checking the return val.
+      ::WaitForSingleObject(winproc_event, sandbox::SboxTestEventTimeout());
+    } else {
+      // Ensure no strays.
+      ::TerminateProcess(proc_info.hProcess, 0);
+      ADD_FAILURE();
+    }
+    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
+    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
+  }
+}
+
+//------------------------------------------------------------------------------
+// ExtensionPoint test helper function.
+//
+// 1. Set up the AppInit Dll in registry settings. (Enable)
+// 2. Spawn a Windows process (with or without mitigation enabled).
+// 3. Check if the AppInit Dll got loaded in the Windows process or not.
+// 4. Signal the Windows process to shutdown.
+// 5. Restore original reg settings.
+//
+// Do NOT use any ASSERTs in this function.  Cleanup required.
+//------------------------------------------------------------------------------
+void TestWin8ExtensionPointAppInitWrapper(bool is_success_test) {
+  // 0.5 Get path of current module.  The appropriate build of the
+  //     AppInit DLL will be in the same directory (and the
+  //     full path is needed for reg).
+  wchar_t path[MAX_PATH];
+  if (!::GetModuleFileNameW(NULL, path, MAX_PATH)) {
+    ADD_FAILURE();
+    return;
+  }
+  // Only want the directory.  Switch file name for the AppInit DLL.
+  base::FilePath full_dll_path(path);
+  full_dll_path = full_dll_path.DirName();
+  full_dll_path = full_dll_path.Append(hooking_dll::g_hook_dll_file);
+  wchar_t* non_const = const_cast<wchar_t*>(full_dll_path.value().c_str());
+  // Now make sure the path is in "short-name" form for registry.
+  DWORD length = ::GetShortPathNameW(non_const, NULL, 0);
+  std::vector<wchar_t> short_name(length);
+  if (!::GetShortPathNameW(non_const, &short_name[0], length)) {
+    ADD_FAILURE();
+    return;
+  }
+
+  // 1. Reg setup.
+  const wchar_t* app_init_reg_path =
+      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
+  const wchar_t* dlls_value_name = L"AppInit_DLLs";
+  const wchar_t* enabled_value_name = L"LoadAppInit_DLLs";
+  const wchar_t* signing_value_name = L"RequireSignedAppInit_DLLs";
+  base::string16 orig_dlls;
+  base::string16 new_dlls;
+  DWORD orig_enabled_value = 0;
+  DWORD orig_signing_value = 0;
+  base::win::RegKey app_init_key(HKEY_LOCAL_MACHINE, app_init_reg_path,
+                                 KEY_QUERY_VALUE | KEY_SET_VALUE);
+  // Backup the existing settings.
+  if (!app_init_key.Valid() || !app_init_key.HasValue(dlls_value_name) ||
+      !app_init_key.HasValue(enabled_value_name) ||
+      ERROR_SUCCESS != app_init_key.ReadValue(dlls_value_name, &orig_dlls) ||
+      ERROR_SUCCESS !=
+          app_init_key.ReadValueDW(enabled_value_name, &orig_enabled_value)) {
+    ADD_FAILURE();
+    return;
+  }
+  if (app_init_key.HasValue(signing_value_name)) {
+    if (ERROR_SUCCESS !=
+        app_init_key.ReadValueDW(signing_value_name, &orig_signing_value)) {
+      ADD_FAILURE();
+      return;
+    }
+  }
+
+  // Set the new settings (obviously requires local admin privileges).
+  new_dlls = orig_dlls;
+  if (!orig_dlls.empty())
+    new_dlls.append(L",");
+  new_dlls.append(short_name.data());
+
+  // From this point on, no return on failure.  Cleanup required.
+  bool all_good = true;
+
+  if (app_init_key.HasValue(signing_value_name)) {
+    if (ERROR_SUCCESS !=
+        app_init_key.WriteValue(signing_value_name, static_cast<DWORD>(0))) {
+      ADD_FAILURE();
+      all_good = false;
+    }
+  }
+  if (ERROR_SUCCESS !=
+          app_init_key.WriteValue(dlls_value_name, new_dlls.c_str()) ||
+      ERROR_SUCCESS !=
+          app_init_key.WriteValue(enabled_value_name, static_cast<DWORD>(1))) {
+    ADD_FAILURE();
+    all_good = false;
+  }
+
+  // 2. Spawn WinProc.
+  HANDLE winproc_event = INVALID_HANDLE_VALUE;
+  base::win::ScopedHandle scoped_event;
+  PROCESS_INFORMATION proc_info = {};
+  if (all_good) {
+    winproc_event =
+        ::CreateEventW(NULL, FALSE, FALSE, hooking_win_proc::g_winproc_event);
+    if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
+      ADD_FAILURE();
+      all_good = false;
+    } else {
+      scoped_event.Set(winproc_event);
+      if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
+        all_good = false;
+    }
+  }
+
+  // 3. Check loaded modules in WinProc to see if the AppInit dll is loaded.
+  bool dll_loaded = false;
+  if (all_good) {
+    std::vector<HMODULE>(modules);
+    if (!base::win::GetLoadedModulesSnapshot(proc_info.hProcess, &modules)) {
+      ADD_FAILURE();
+      all_good = false;
+    } else {
+      for (HMODULE module : modules) {
+        wchar_t name[MAX_PATH] = {};
+        if (::GetModuleFileNameExW(proc_info.hProcess, module, name,
+                                   MAX_PATH) &&
+            ::wcsstr(name, hooking_dll::g_hook_dll_file)) {
+          // Found it.
+          dll_loaded = true;
+          break;
+        }
+      }
+    }
+  }
+
+  // Was the test result as expected?
+  if (all_good)
+    EXPECT_EQ((is_success_test ? true : false), dll_loaded);
+
+  // 4. Trigger shutdown of WinProc.
+  if (proc_info.hProcess) {
+    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
+      ::WaitForSingleObject(winproc_event, sandbox::SboxTestEventTimeout());
+    } else {
+      // Ensure no strays.
+      ::TerminateProcess(proc_info.hProcess, 0);
+      ADD_FAILURE();
+    }
+    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
+    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
+  }
+
+  // 5. Reg Restore
+  EXPECT_EQ(ERROR_SUCCESS,
+            app_init_key.WriteValue(enabled_value_name, orig_enabled_value));
+  if (app_init_key.HasValue(signing_value_name))
+    EXPECT_EQ(ERROR_SUCCESS,
+              app_init_key.WriteValue(signing_value_name, orig_signing_value));
+  EXPECT_EQ(ERROR_SUCCESS,
+            app_init_key.WriteValue(dlls_value_name, orig_dlls.c_str()));
+}
+
+}  // namespace
+
+namespace sandbox {
+
+//------------------------------------------------------------------------------
+// Exported Extension Point Tests
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Disable extension points (MITIGATION_EXTENSION_POINT_DISABLE).
+// >= Win8
+//------------------------------------------------------------------------------
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckWin8ExtensionPointPolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(sandbox::TESTPOLICY_EXTENSIONPOINT);
+
+  //---------------------------------
+  // 1) Test setting pre-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_EXTENSION_POINT_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+  //---------------------------------
+  // 2) Test setting post-startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
+
+  EXPECT_EQ(
+      policy2->SetDelayedProcessMitigations(MITIGATION_EXTENSION_POINT_DISABLE),
+      SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
+
+// This test validates that a "legitimate" global hook CAN be set on the
+// sandboxed proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation is not set.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest,
+     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(true, true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation prevents a global hook on WinProc.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest,
+     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(false, true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that a "legitimate" hook CAN be set on the sandboxed
+// proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(true, false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// *** Important: MITIGATION_EXTENSION_POINT_DISABLE does NOT prevent
+// hooks targetted at a specific thread id.  It only prevents
+// global hooks.  So this test does NOT actually expect the hook
+// to fail (see TestWin8ExtensionPointHookWrapper function) even
+// with the mitigation on.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(false, false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that an AppInit Dll CAN be added to a target
+// WinProc if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
+//
+// MANUAL testing only.
+// Must run this test as admin/elevated.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  TestWin8ExtensionPointAppInitWrapper(true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation prevents the loading of any AppInit Dll into WinProc.
+//
+// MANUAL testing only.
+// Must run this test as admin/elevated.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL);
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(mutex, SboxTestEventTimeout()));
+
+  TestWin8ExtensionPointAppInitWrapper(false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_imageload_unittest.cc b/sandbox/win/src/process_mitigations_imageload_unittest.cc
new file mode 100644
index 0000000..41c652e
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_imageload_unittest.cc
@@ -0,0 +1,248 @@
+// 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 "sandbox/win/src/process_mitigations.h"
+
+#include <windows.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/scoped_native_library.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Internal Defines & Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// ImageLoadRemote test helper function.
+//
+// Trigger test child process (with or without mitigation enabled).
+//------------------------------------------------------------------------------
+void TestWin10ImageLoadRemote(bool is_success_test) {
+  // ***Insert a manual testing share UNC path here!
+  // E.g.: \\\\hostname\\sharename\\calc.exe
+  base::string16 unc = L"\"\\\\hostname\\sharename\\calc.exe\"";
+
+  sandbox::TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Set a policy that would normally allow for process creation.
+  policy->SetJobLevel(sandbox::JOB_NONE, 0);
+  policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
+  runner.SetDisableCsrss(false);
+
+  if (!is_success_test) {
+    // Enable the NoRemote mitigation.
+    EXPECT_EQ(policy->SetDelayedProcessMitigations(
+                  sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE),
+              sandbox::SBOX_ALL_OK);
+  }
+
+  base::string16 test = L"TestChildProcess ";
+  test += unc.c_str();
+  EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED
+                             : sandbox::SBOX_TEST_FAILED),
+            runner.RunTest(test.c_str()));
+}
+
+//------------------------------------------------------------------------------
+// ImageLoadLow test helper function.
+//
+// 1. Set up a copy of calc, using icacls to make it low integrity.
+// 2. Trigger test child process (with or without mitigation enabled).
+//------------------------------------------------------------------------------
+void TestWin10ImageLoadLowLabel(bool is_success_test) {
+  // Setup a mandatory low executable for this test (calc.exe).
+  // If anything fails during setup, ASSERT to end test.
+  base::FilePath orig_path;
+  ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &orig_path));
+  orig_path = orig_path.Append(L"calc.exe");
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath new_path = temp_dir.GetPath();
+  new_path = new_path.Append(L"lowIL_calc.exe");
+
+  // Test file will be cleaned up by the ScopedTempDir.
+  ASSERT_TRUE(base::CopyFileW(orig_path, new_path));
+
+  base::string16 cmd_line = L"icacls \"";
+  cmd_line += new_path.value().c_str();
+  cmd_line += L"\" /setintegritylevel Low";
+
+  base::LaunchOptions options = base::LaunchOptionsForTest();
+  base::Process setup_proc = base::LaunchProcess(cmd_line.c_str(), options);
+  ASSERT_TRUE(setup_proc.IsValid());
+
+  int exit_code = 1;
+  if (!setup_proc.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+                                         &exit_code)) {
+    // Might have timed out, or might have failed.
+    // Terminate to make sure we clean up any mess.
+    setup_proc.Terminate(0, false);
+    ASSERT_TRUE(false);
+  }
+  // Make sure icacls was successful.
+  ASSERT_EQ(0, exit_code);
+
+  sandbox::TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Set a policy that would normally allow for process creation.
+  policy->SetJobLevel(sandbox::JOB_NONE, 0);
+  policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
+  runner.SetDisableCsrss(false);
+
+  if (!is_success_test) {
+    // Enable the NoLowLabel mitigation.
+    EXPECT_EQ(policy->SetDelayedProcessMitigations(
+                  sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL),
+              sandbox::SBOX_ALL_OK);
+  }
+
+  base::string16 test = L"TestChildProcess \"";
+  test += new_path.value().c_str();
+  test += L"\" false";
+
+  EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED
+                             : sandbox::SBOX_TEST_FAILED),
+            runner.RunTest(test.c_str()));
+}
+
+}  // namespace
+
+namespace sandbox {
+
+//------------------------------------------------------------------------------
+// Exported Image Load Tests
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Disable image load from remote devices (MITIGATION_IMAGE_LOAD_NO_REMOTE).
+// >= Win10_TH2
+//------------------------------------------------------------------------------
+
+// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE
+// mitigation enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoRemotePolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_LOADNOREMOTE);
+
+  //---------------------------------
+  // 1) Test setting pre-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_IMAGE_LOAD_NO_REMOTE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+  //---------------------------------
+  // 2) Test setting post-startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
+
+  EXPECT_EQ(
+      policy2->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_REMOTE),
+      SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
+
+// This test validates that we CAN create a new process from
+// a remote UNC device, if the MITIGATION_IMAGE_LOAD_NO_REMOTE
+// mitigation is NOT set.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  TestWin10ImageLoadRemote(true);
+}
+
+// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE
+// mitigation prevents creating a new process from a remote
+// UNC device.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  TestWin10ImageLoadRemote(false);
+}
+
+//------------------------------------------------------------------------------
+// Disable image load when "mandatory low label" (integrity level).
+// (MITIGATION_IMAGE_LOAD_NO_LOW_LABEL)
+// >= Win10_TH2
+//------------------------------------------------------------------------------
+
+// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
+// mitigation enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelPolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_LOADNOLOW);
+
+  //---------------------------------
+  // 1) Test setting pre-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_IMAGE_LOAD_NO_LOW_LABEL),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+  //---------------------------------
+  // 2) Test setting post-startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
+
+  EXPECT_EQ(
+      policy2->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_LOW_LABEL),
+      SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
+
+// This test validates that we CAN create a new process with
+// low mandatory label (IL), if the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
+// mitigation is NOT set.
+TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  TestWin10ImageLoadLowLabel(true);
+}
+
+// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
+// mitigation prevents creating a new process with low mandatory label (IL).
+TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
+    return;
+
+  TestWin10ImageLoadLowLabel(false);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
deleted file mode 100644
index 1e6b3420..0000000
--- a/sandbox/win/src/process_mitigations_test.cc
+++ /dev/null
@@ -1,1814 +0,0 @@
-// Copyright 2011 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 "sandbox/win/src/process_mitigations.h"
-
-#include <d3d9.h>
-#include <initguid.h>
-#include <opmapi.h>
-#include <psapi.h>
-#include <windows.h>
-
-#include <map>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
-#include "base/process/launch.h"
-#include "base/scoped_native_library.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_timeouts.h"
-#include "base/win/registry.h"
-#include "base/win/scoped_handle.h"
-#include "base/win/startup_information.h"
-#include "base/win/win_util.h"
-#include "base/win/windows_version.h"
-#include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/process_mitigations_win32k_policy.h"
-#include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sandbox_factory.h"
-#include "sandbox/win/src/target_services.h"
-#include "sandbox/win/tests/common/controller.h"
-#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Timeouts for synchronization.
-#define event_timeout \
-  static_cast<DWORD>((TestTimeouts::action_timeout()).InMillisecondsRoundedUp())
-
-// API defined in winbase.h.
-typedef decltype(GetProcessDEPPolicy)* GetProcessDEPPolicyFunction;
-
-// API defined in processthreadsapi.h.
-typedef decltype(
-    GetProcessMitigationPolicy)* GetProcessMitigationPolicyFunction;
-GetProcessMitigationPolicyFunction get_process_mitigation_policy;
-
-// APIs defined in wingdi.h.
-typedef decltype(AddFontMemResourceEx)* AddFontMemResourceExFunction;
-typedef decltype(RemoveFontMemResourceEx)* RemoveFontMemResourceExFunction;
-
-// APIs defined in integration_tests_common.h
-typedef decltype(WasHookCalled)* WasHookCalledFunction;
-typedef decltype(SetHook)* SetHookFunction;
-
-#if !defined(_WIN64)
-bool CheckWin8DepPolicy() {
-  PROCESS_MITIGATION_DEP_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy,
-                                     &policy, sizeof(policy))) {
-    return false;
-  }
-  return policy.Enable && policy.Permanent;
-}
-#endif  // !defined(_WIN64)
-
-bool CheckWin8AslrPolicy() {
-  PROCESS_MITIGATION_ASLR_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy,
-                                     &policy, sizeof(policy))) {
-    return false;
-  }
-  return policy.EnableForceRelocateImages && policy.DisallowStrippedImages;
-}
-
-bool CheckWin8StrictHandlePolicy() {
-  PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessStrictHandleCheckPolicy, &policy,
-                                     sizeof(policy))) {
-    return false;
-  }
-  return policy.RaiseExceptionOnInvalidHandleReference &&
-         policy.HandleExceptionsPermanentlyEnabled;
-}
-
-bool CheckWin8Win32CallPolicy() {
-  PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessSystemCallDisablePolicy, &policy,
-                                     sizeof(policy))) {
-    return false;
-  }
-  return policy.DisallowWin32kSystemCalls;
-}
-
-bool CheckWin8ExtensionPointPolicy() {
-  PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessExtensionPointDisablePolicy,
-                                     &policy, sizeof(policy))) {
-    return false;
-  }
-  return policy.DisableExtensionPoints;
-}
-
-bool CheckWin10FontPolicy() {
-  PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessFontDisablePolicy, &policy,
-                                     sizeof(policy))) {
-    return false;
-  }
-  return policy.DisableNonSystemFonts;
-}
-
-bool CheckWin10ImageLoadNoRemotePolicy() {
-  PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessImageLoadPolicy, &policy,
-                                     sizeof(policy))) {
-    return false;
-  }
-  return policy.NoRemoteImages;
-}
-
-// Spawn Windows process (with or without mitigation enabled).
-bool SpawnWinProc(PROCESS_INFORMATION* pi, bool success_test, HANDLE* event) {
-  base::win::StartupInformation startup_info;
-  DWORD creation_flags = 0;
-
-  if (!success_test) {
-    DWORD64 flags =
-        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
-    // This test only runs on >= Win8, so don't have to handle
-    // illegal 64-bit flags on 32-bit <= Win7.
-    size_t flags_size = sizeof(flags);
-
-    if (!startup_info.InitializeProcThreadAttributeList(1) ||
-        !startup_info.UpdateProcThreadAttribute(
-            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &flags, flags_size)) {
-      ADD_FAILURE();
-      return false;
-    }
-    creation_flags = EXTENDED_STARTUPINFO_PRESENT;
-  }
-
-  // Command line must be writable.
-  base::string16 cmd_writeable(g_winproc_file);
-
-  if (!::CreateProcessW(NULL, &cmd_writeable[0], NULL, NULL, FALSE,
-                        creation_flags, NULL, NULL, startup_info.startup_info(),
-                        pi)) {
-    ADD_FAILURE();
-    return false;
-  }
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(*event, event_timeout));
-
-  return true;
-}
-
-//------------------------------------------------------------------------------
-// 1. Spawn a Windows process (with or without mitigation enabled).
-// 2. Load the hook Dll locally.
-// 3. Create a global named event for the hook to trigger.
-// 4. Start the hook (for the specific WinProc or globally).
-// 5. Send a keystroke event.
-// 6. Ask the hook Dll if it received a hook callback.
-// 7. Cleanup the hooking.
-// 8. Signal the Windows process to shutdown.
-//
-// Do NOT use any ASSERTs in this function.  Cleanup required.
-//------------------------------------------------------------------------------
-void TestWin8ExtensionPointHookWrapper(bool is_success_test, bool global_hook) {
-  // Set up a couple global events that this test will use.
-  HANDLE winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event);
-  if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
-    ADD_FAILURE();
-    return;
-  }
-  base::win::ScopedHandle scoped_winproc_event(winproc_event);
-
-  HANDLE hook_event = ::CreateEventW(NULL, FALSE, FALSE, g_hook_event);
-  if (hook_event == NULL || hook_event == INVALID_HANDLE_VALUE) {
-    ADD_FAILURE();
-    return;
-  }
-  base::win::ScopedHandle scoped_hook_event(hook_event);
-
-  // 1. Spawn WinProc.
-  PROCESS_INFORMATION proc_info = {};
-  if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
-    return;
-
-  // From this point on, no return on failure.  Cleanup required.
-  bool all_good = true;
-
-  // 2. Load the hook DLL.
-  base::FilePath hook_dll_path(g_hook_dll_file);
-  base::ScopedNativeLibrary dll(hook_dll_path);
-  EXPECT_TRUE(dll.is_valid());
-
-  HOOKPROC hook_proc =
-      reinterpret_cast<HOOKPROC>(dll.GetFunctionPointer(g_hook_handler_func));
-  WasHookCalledFunction was_hook_called =
-      reinterpret_cast<WasHookCalledFunction>(
-          dll.GetFunctionPointer(g_was_hook_called_func));
-  SetHookFunction set_hook = reinterpret_cast<SetHookFunction>(
-      dll.GetFunctionPointer(g_set_hook_func));
-  if (!hook_proc || !was_hook_called || !set_hook) {
-    ADD_FAILURE();
-    all_good = false;
-  }
-
-  // 3. Try installing the hook (either on a remote target thread,
-  //    or globally).
-  HHOOK hook = nullptr;
-  if (all_good) {
-    DWORD target = 0;
-    if (!global_hook)
-      target = proc_info.dwThreadId;
-    hook = ::SetWindowsHookExW(WH_KEYBOARD, hook_proc, dll.get(), target);
-    if (!hook) {
-      ADD_FAILURE();
-      all_good = false;
-    } else
-      // Pass the hook DLL the hook handle.
-      set_hook(hook);
-  }
-
-  // 4. Inject a keyboard event.
-  if (all_good) {
-    // Note: that PostThreadMessage and SendMessage APIs will not deliver
-    // a keystroke in such a way that triggers a "legitimate" hook.
-    // Have to use targetless SendInput or keybd_event.  The latter is
-    // less code and easier to work with.
-    keybd_event(VkKeyScan(L'A'), 0, 0, 0);
-    keybd_event(VkKeyScan(L'A'), 0, KEYEVENTF_KEYUP, 0);
-    // Give it a chance to hit the hook handler...
-    ::WaitForSingleObject(hook_event, event_timeout);
-
-    // 5. Did the hook get hit?  Was it expected to?
-    if (global_hook)
-      EXPECT_EQ((is_success_test ? true : false), was_hook_called());
-    else
-      // ***IMPORTANT: when targeting a specific thread id, the
-      // PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE
-      // mitigation does NOT disable the hook API.  It ONLY
-      // stops global hooks from running in a process.  Hence,
-      // the hook will hit (TRUE) even in the "failure"
-      // case for a non-global/targeted hook.
-      EXPECT_EQ((is_success_test ? true : true), was_hook_called());
-  }
-
-  // 6. Disable hook.
-  if (hook)
-    EXPECT_TRUE(::UnhookWindowsHookEx(hook));
-
-  // 7. Trigger shutdown of WinProc.
-  if (proc_info.hProcess) {
-    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
-      // Note: The combination/perfect-storm of a Global Hook, in a
-      // WinProc that has the EXTENSION_POINT_DISABLE mitigation ON, and the
-      // use of the SendInput or keybd_event API to inject a keystroke,
-      // results in the target becoming unresponsive.  If any one of these
-      // states are changed, the problem does not occur.  This means the WM_QUIT
-      // message is not handled and the call to WaitForSingleObject times out.
-      // Therefore not checking the return val.
-      ::WaitForSingleObject(winproc_event, event_timeout);
-    } else {
-      // Ensure no strays.
-      ::TerminateProcess(proc_info.hProcess, 0);
-      ADD_FAILURE();
-    }
-    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
-    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
-  }
-}
-
-//------------------------------------------------------------------------------
-// 1. Set up the AppInit Dll in registry settings. (Enable)
-// 2. Spawn a Windows process (with or without mitigation enabled).
-// 3. Check if the AppInit Dll got loaded in the Windows process or not.
-// 4. Signal the Windows process to shutdown.
-// 5. Restore original reg settings.
-//
-// Do NOT use any ASSERTs in this function.  Cleanup required.
-//------------------------------------------------------------------------------
-void TestWin8ExtensionPointAppInitWrapper(bool is_success_test) {
-  // 0.5 Get path of current module.  The appropriate build of the
-  //     AppInit DLL will be in the same directory (and the
-  //     full path is needed for reg).
-  wchar_t path[MAX_PATH];
-  if (!::GetModuleFileNameW(NULL, path, MAX_PATH)) {
-    ADD_FAILURE();
-    return;
-  }
-  // Only want the directory.  Switch file name for the AppInit DLL.
-  base::FilePath full_dll_path(path);
-  full_dll_path = full_dll_path.DirName();
-  full_dll_path = full_dll_path.Append(g_hook_dll_file);
-  wchar_t* non_const = const_cast<wchar_t*>(full_dll_path.value().c_str());
-  // Now make sure the path is in "short-name" form for registry.
-  DWORD length = ::GetShortPathNameW(non_const, NULL, 0);
-  std::vector<wchar_t> short_name(length);
-  if (!::GetShortPathNameW(non_const, &short_name[0], length)) {
-    ADD_FAILURE();
-    return;
-  }
-
-  // 1. Reg setup.
-  const wchar_t* app_init_reg_path =
-      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
-  const wchar_t* dlls_value_name = L"AppInit_DLLs";
-  const wchar_t* enabled_value_name = L"LoadAppInit_DLLs";
-  const wchar_t* signing_value_name = L"RequireSignedAppInit_DLLs";
-  std::wstring orig_dlls;
-  std::wstring new_dlls;
-  DWORD orig_enabled_value = 0;
-  DWORD orig_signing_value = 0;
-  base::win::RegKey app_init_key(HKEY_LOCAL_MACHINE, app_init_reg_path,
-                                 KEY_QUERY_VALUE | KEY_SET_VALUE);
-  // Backup the existing settings.
-  if (!app_init_key.Valid() || !app_init_key.HasValue(dlls_value_name) ||
-      !app_init_key.HasValue(enabled_value_name) ||
-      ERROR_SUCCESS != app_init_key.ReadValue(dlls_value_name, &orig_dlls) ||
-      ERROR_SUCCESS !=
-          app_init_key.ReadValueDW(enabled_value_name, &orig_enabled_value)) {
-    ADD_FAILURE();
-    return;
-  }
-  if (app_init_key.HasValue(signing_value_name)) {
-    if (ERROR_SUCCESS !=
-        app_init_key.ReadValueDW(signing_value_name, &orig_signing_value)) {
-      ADD_FAILURE();
-      return;
-    }
-  }
-
-  // Set the new settings (obviously requires local admin privileges).
-  new_dlls = orig_dlls;
-  if (!orig_dlls.empty())
-    new_dlls.append(L",");
-  new_dlls.append(short_name.data());
-
-  // From this point on, no return on failure.  Cleanup required.
-  bool all_good = true;
-
-  if (app_init_key.HasValue(signing_value_name)) {
-    if (ERROR_SUCCESS !=
-        app_init_key.WriteValue(signing_value_name, static_cast<DWORD>(0))) {
-      ADD_FAILURE();
-      all_good = false;
-    }
-  }
-  if (ERROR_SUCCESS !=
-          app_init_key.WriteValue(dlls_value_name, new_dlls.c_str()) ||
-      ERROR_SUCCESS !=
-          app_init_key.WriteValue(enabled_value_name, static_cast<DWORD>(1))) {
-    ADD_FAILURE();
-    all_good = false;
-  }
-
-  // 2. Spawn WinProc.
-  HANDLE winproc_event = INVALID_HANDLE_VALUE;
-  base::win::ScopedHandle scoped_event;
-  PROCESS_INFORMATION proc_info = {};
-  if (all_good) {
-    winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event);
-    if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
-      ADD_FAILURE();
-      all_good = false;
-    } else {
-      scoped_event.Set(winproc_event);
-      if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
-        all_good = false;
-    }
-  }
-
-  // 3. Check loaded modules in WinProc to see if the AppInit dll is loaded.
-  bool dll_loaded = false;
-  if (all_good) {
-    std::vector<HMODULE>(modules);
-    if (!base::win::GetLoadedModulesSnapshot(proc_info.hProcess, &modules)) {
-      ADD_FAILURE();
-      all_good = false;
-    } else {
-      for (HMODULE module : modules) {
-        wchar_t name[MAX_PATH] = {};
-        if (::GetModuleFileNameExW(proc_info.hProcess, module, name,
-                                   MAX_PATH) &&
-            ::wcsstr(name, g_hook_dll_file)) {
-          // Found it.
-          dll_loaded = true;
-          break;
-        }
-      }
-    }
-  }
-
-  // Was the test result as expected?
-  if (all_good)
-    EXPECT_EQ((is_success_test ? true : false), dll_loaded);
-
-  // 4. Trigger shutdown of WinProc.
-  if (proc_info.hProcess) {
-    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
-      ::WaitForSingleObject(winproc_event, event_timeout);
-    } else {
-      // Ensure no strays.
-      ::TerminateProcess(proc_info.hProcess, 0);
-      ADD_FAILURE();
-    }
-    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
-    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
-  }
-
-  // 5. Reg Restore
-  EXPECT_EQ(ERROR_SUCCESS,
-            app_init_key.WriteValue(enabled_value_name, orig_enabled_value));
-  if (app_init_key.HasValue(signing_value_name))
-    EXPECT_EQ(ERROR_SUCCESS,
-              app_init_key.WriteValue(signing_value_name, orig_signing_value));
-  EXPECT_EQ(ERROR_SUCCESS,
-            app_init_key.WriteValue(dlls_value_name, orig_dlls.c_str()));
-}
-
-void TestWin10ImageLoadRemote(bool is_success_test) {
-  // ***Insert a manual testing share UNC path here!
-  // E.g.: \\\\hostname\\sharename\\calc.exe
-  std::wstring unc = L"\"\\\\hostname\\sharename\\calc.exe\"";
-
-  sandbox::TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // Set a policy that would normally allow for process creation.
-  policy->SetJobLevel(sandbox::JOB_NONE, 0);
-  policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
-  runner.SetDisableCsrss(false);
-
-  if (!is_success_test) {
-    // Enable the NoRemote mitigation.
-    EXPECT_EQ(policy->SetDelayedProcessMitigations(
-                  sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE),
-              sandbox::SBOX_ALL_OK);
-  }
-
-  std::wstring test = L"TestChildProcess ";
-  test += unc.c_str();
-  EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED
-                             : sandbox::SBOX_TEST_FAILED),
-            runner.RunTest(test.c_str()));
-}
-
-bool CheckWin10ImageLoadNoLowLabelPolicy() {
-  PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
-  if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessImageLoadPolicy, &policy,
-                                     sizeof(policy))) {
-    return false;
-  }
-  return policy.NoLowMandatoryLabelImages;
-}
-
-void TestWin10ImageLoadLowLabel(bool is_success_test) {
-  // Setup a mandatory low executable for this test (calc.exe).
-  // If anything fails during setup, ASSERT to end test.
-  base::FilePath orig_path;
-  ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &orig_path));
-  orig_path = orig_path.Append(L"calc.exe");
-
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  base::FilePath new_path = temp_dir.GetPath();
-  new_path = new_path.Append(L"lowIL_calc.exe");
-
-  // Test file will be cleaned up by the ScopedTempDir.
-  ASSERT_TRUE(base::CopyFileW(orig_path, new_path));
-
-  std::wstring cmd_line = L"icacls \"";
-  cmd_line += new_path.value().c_str();
-  cmd_line += L"\" /setintegritylevel Low";
-
-  base::LaunchOptions options = base::LaunchOptionsForTest();
-  base::Process setup_proc = base::LaunchProcess(cmd_line.c_str(), options);
-  ASSERT_TRUE(setup_proc.IsValid());
-
-  int exit_code = 1;
-  if (!setup_proc.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(10),
-                                         &exit_code)) {
-    // Might have timed out, or might have failed.
-    // Terminate to make sure we clean up any mess.
-    setup_proc.Terminate(0, false);
-    ASSERT_TRUE(false);
-  }
-  // Make sure icacls was successful.
-  ASSERT_EQ(0, exit_code);
-
-  sandbox::TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // Set a policy that would normally allow for process creation.
-  policy->SetJobLevel(sandbox::JOB_NONE, 0);
-  policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
-  runner.SetDisableCsrss(false);
-
-  if (!is_success_test) {
-    // Enable the NoLowLabel mitigation.
-    EXPECT_EQ(policy->SetDelayedProcessMitigations(
-                  sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL),
-              sandbox::SBOX_ALL_OK);
-  }
-
-  std::wstring test = L"TestChildProcess ";
-  test += new_path.value().c_str();
-
-  EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED
-                             : sandbox::SBOX_TEST_FAILED),
-            runner.RunTest(test.c_str()));
-}
-
-BOOL CALLBACK MonitorEnumCallback(HMONITOR monitor,
-                                  HDC hdc_monitor,
-                                  LPRECT rect_monitor,
-                                  LPARAM data) {
-  std::map<HMONITOR, base::string16>& monitors =
-      *reinterpret_cast<std::map<HMONITOR, base::string16>*>(data);
-  MONITORINFOEXW monitor_info = {};
-  monitor_info.cbSize = sizeof(monitor_info);
-
-  if (!::GetMonitorInfoW(monitor,
-                         reinterpret_cast<MONITORINFO*>(&monitor_info)))
-    return FALSE;
-  monitors[monitor] = monitor_info.szDevice;
-  return TRUE;
-}
-
-std::map<HMONITOR, std::wstring> EnumerateMonitors() {
-  std::map<HMONITOR, std::wstring> result;
-  ::EnumDisplayMonitors(nullptr, nullptr, MonitorEnumCallback,
-                        reinterpret_cast<LPARAM>(&result));
-  return result;
-}
-
-#define HMONITOR_ENTRY(monitor)                 \
-  result[reinterpret_cast<HMONITOR>(monitor)] = \
-      base::StringPrintf(L"\\\\.\\DISPLAY%X", monitor)
-
-std::map<HMONITOR, std::wstring> GetTestMonitors() {
-  std::map<HMONITOR, std::wstring> result;
-
-  HMONITOR_ENTRY(0x11111111);
-  HMONITOR_ENTRY(0x22222222);
-  HMONITOR_ENTRY(0x44444444);
-  HMONITOR_ENTRY(0x88888888);
-  return result;
-}
-
-std::wstring UnicodeStringToString(PUNICODE_STRING name) {
-  return std::wstring(name->Buffer,
-                      name->Buffer + (name->Length / sizeof(name->Buffer[0])));
-}
-
-// Returns an index 1, 2, 4 or 8 depening on the device. 0 on error.
-DWORD GetTestDeviceMonitorIndex(PUNICODE_STRING device_name) {
-  std::wstring name = UnicodeStringToString(device_name);
-  std::map<HMONITOR, std::wstring> monitors = GetTestMonitors();
-  for (const auto& monitor : monitors) {
-    if (name == monitor.second)
-      return static_cast<DWORD>(reinterpret_cast<uintptr_t>(monitor.first)) &
-             0xF;
-  }
-  return 0;
-}
-
-NTSTATUS WINAPI GetSuggestedOPMProtectedOutputArraySizeTest(
-    PUNICODE_STRING device_name,
-    DWORD* suggested_output_array_size) {
-  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
-  if (!monitor)
-    return STATUS_OBJECT_NAME_NOT_FOUND;
-  *suggested_output_array_size = monitor;
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI
-CreateOPMProtectedOutputsTest(PUNICODE_STRING device_name,
-                              DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
-                              DWORD output_array_size,
-                              DWORD* num_in_output_array,
-                              OPM_PROTECTED_OUTPUT_HANDLE* output_array) {
-  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
-  if (!monitor)
-    return STATUS_OBJECT_NAME_NOT_FOUND;
-  if (vos != DXGKMDT_OPM_VOS_OPM_SEMANTICS)
-    return STATUS_INVALID_PARAMETER;
-  if (output_array_size != monitor)
-    return STATUS_INVALID_PARAMETER;
-  *num_in_output_array = monitor - 1;
-  for (DWORD index = 0; index < monitor - 1; ++index) {
-    output_array[index] =
-        reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE>((monitor << 4) + index);
-  }
-  return STATUS_SUCCESS;
-}
-
-ULONG CalculateCertLength(ULONG monitor) {
-  return (monitor * 0x800) + 0xabc;
-}
-
-NTSTATUS WINAPI GetCertificateTest(PUNICODE_STRING device_name,
-                                   DXGKMDT_CERTIFICATE_TYPE certificate_type,
-                                   BYTE* certificate,
-                                   ULONG certificate_length) {
-  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
-  if (!monitor)
-    return STATUS_OBJECT_NAME_NOT_FOUND;
-  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
-    return STATUS_INVALID_PARAMETER;
-  if (certificate_length != CalculateCertLength(monitor))
-    return STATUS_INVALID_PARAMETER;
-  memset(certificate, 'A' + monitor, certificate_length);
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI
-GetCertificateSizeTest(PUNICODE_STRING device_name,
-                       DXGKMDT_CERTIFICATE_TYPE certificate_type,
-                       ULONG* certificate_length) {
-  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
-  if (!monitor)
-    return STATUS_OBJECT_NAME_NOT_FOUND;
-  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
-    return STATUS_INVALID_PARAMETER;
-  *certificate_length = CalculateCertLength(monitor);
-  return STATUS_SUCCESS;
-}
-
-// Check for valid output handle and return the monitor index.
-DWORD IsValidProtectedOutput(OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
-  uintptr_t handle = reinterpret_cast<uintptr_t>(protected_output);
-  uintptr_t monitor = handle >> 4;
-  uintptr_t index = handle & 0xF;
-  switch (monitor) {
-    case 1:
-    case 2:
-    case 4:
-    case 8:
-      break;
-    default:
-      return 0;
-  }
-  if (index >= (monitor - 1))
-    return 0;
-  return static_cast<DWORD>(monitor);
-}
-
-NTSTATUS WINAPI
-GetCertificateByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-                           DXGKMDT_CERTIFICATE_TYPE certificate_type,
-                           BYTE* certificate,
-                           ULONG certificate_length) {
-  DWORD monitor = IsValidProtectedOutput(protected_output);
-  if (!monitor)
-    return STATUS_INVALID_HANDLE;
-  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
-    return STATUS_INVALID_PARAMETER;
-  if (certificate_length != CalculateCertLength(monitor))
-    return STATUS_INVALID_PARAMETER;
-  memset(certificate, 'A' + monitor, certificate_length);
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI
-GetCertificateSizeByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-                               DXGKMDT_CERTIFICATE_TYPE certificate_type,
-                               ULONG* certificate_length) {
-  DWORD monitor = IsValidProtectedOutput(protected_output);
-  if (!monitor)
-    return STATUS_INVALID_HANDLE;
-  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
-    return STATUS_INVALID_PARAMETER;
-  *certificate_length = CalculateCertLength(monitor);
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI
-DestroyOPMProtectedOutputTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
-  if (!IsValidProtectedOutput(protected_output))
-    return STATUS_INVALID_HANDLE;
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI ConfigureOPMProtectedOutputTest(
-    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-    const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
-    ULONG additional_parameters_size,
-    const BYTE* additional_parameters) {
-  if (!IsValidProtectedOutput(protected_output))
-    return STATUS_INVALID_HANDLE;
-  if (additional_parameters && additional_parameters_size)
-    return STATUS_INVALID_PARAMETER;
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI GetOPMInformationTest(
-    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-    const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
-    DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information) {
-  DWORD monitor = IsValidProtectedOutput(protected_output);
-  if (!monitor)
-    return STATUS_INVALID_HANDLE;
-  memset(requested_information, '0' + monitor,
-         sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION));
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI
-GetOPMRandomNumberTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-                       DXGKMDT_OPM_RANDOM_NUMBER* random_number) {
-  DWORD monitor = IsValidProtectedOutput(protected_output);
-  if (!monitor)
-    return STATUS_INVALID_HANDLE;
-  memset(random_number->abRandomNumber, '!' + monitor,
-         sizeof(random_number->abRandomNumber));
-  return STATUS_SUCCESS;
-}
-
-NTSTATUS WINAPI SetOPMSigningKeyAndSequenceNumbersTest(
-    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
-    const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) {
-  DWORD monitor = IsValidProtectedOutput(protected_output);
-  if (!monitor)
-    return STATUS_INVALID_HANDLE;
-  DXGKMDT_OPM_ENCRYPTED_PARAMETERS test_params = {};
-  memset(test_params.abEncryptedParameters, 'a' + monitor,
-         sizeof(test_params.abEncryptedParameters));
-  if (memcmp(test_params.abEncryptedParameters,
-             parameters->abEncryptedParameters,
-             sizeof(test_params.abEncryptedParameters)) != 0)
-    return STATUS_INVALID_PARAMETER;
-  return STATUS_SUCCESS;
-}
-
-BOOL WINAPI EnumDisplayMonitorsTest(HDC hdc,
-                                    LPCRECT clip_rect,
-                                    MONITORENUMPROC enum_function,
-                                    LPARAM data) {
-  RECT rc = {};
-  for (const auto& monitor : GetTestMonitors()) {
-    if (!enum_function(monitor.first, hdc, &rc, data))
-      return FALSE;
-  }
-  return TRUE;
-}
-
-BOOL WINAPI GetMonitorInfoWTest(HMONITOR monitor, LPMONITORINFO monitor_info) {
-  std::map<HMONITOR, std::wstring> monitors = GetTestMonitors();
-  if (monitor_info->cbSize != sizeof(MONITORINFO) &&
-      monitor_info->cbSize != sizeof(MONITORINFOEXW))
-    return FALSE;
-  auto it = monitors.find(monitor);
-  if (it == monitors.end())
-    return FALSE;
-  if (monitor_info->cbSize == sizeof(MONITORINFOEXW)) {
-    MONITORINFOEXW* monitor_info_ex =
-        reinterpret_cast<MONITORINFOEXW*>(monitor_info);
-    size_t copy_size = (it->second.size() + 1) * sizeof(WCHAR);
-    if (copy_size > sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR))
-      copy_size = sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR);
-    memset(monitor_info_ex->szDevice, 0, sizeof(monitor_info_ex->szDevice));
-    memcpy(monitor_info_ex->szDevice, it->second.c_str(), copy_size);
-  }
-  return TRUE;
-}
-
-#define RETURN_TEST_FUNC(n)    \
-  if (strcmp(name, #n) == 0) { \
-    return n##Test;            \
-  }
-
-void* FunctionOverrideForTest(const char* name) {
-  RETURN_TEST_FUNC(GetSuggestedOPMProtectedOutputArraySize);
-  RETURN_TEST_FUNC(CreateOPMProtectedOutputs);
-  RETURN_TEST_FUNC(GetCertificate);
-  RETURN_TEST_FUNC(GetCertificateSize);
-  RETURN_TEST_FUNC(DestroyOPMProtectedOutput);
-  RETURN_TEST_FUNC(ConfigureOPMProtectedOutput);
-  RETURN_TEST_FUNC(GetOPMInformation);
-  RETURN_TEST_FUNC(GetOPMRandomNumber);
-  RETURN_TEST_FUNC(SetOPMSigningKeyAndSequenceNumbers);
-  RETURN_TEST_FUNC(EnumDisplayMonitors);
-  RETURN_TEST_FUNC(GetMonitorInfoW);
-  RETURN_TEST_FUNC(GetCertificateByHandle);
-  RETURN_TEST_FUNC(GetCertificateSizeByHandle);
-  NOTREACHED();
-  return nullptr;
-}
-
-}  // namespace
-
-namespace sandbox {
-
-// A shared helper test command that will attempt to CreateProcess with a given
-// command line. The second optional parameter will cause the child process to
-// return that as an exit code on termination.
-//
-// ***Make sure you've enabled basic process creation in the
-// test sandbox settings via:
-// sandbox::TargetPolicy::SetJobLevel(),
-// sandbox::TargetPolicy::SetTokenLevel(),
-// and TestRunner::SetDisableCsrss().
-SBOX_TESTS_COMMAND int TestChildProcess(int argc, wchar_t** argv) {
-  if (argc < 1)
-    return SBOX_TEST_INVALID_PARAMETER;
-
-  int desired_exit_code = 0;
-
-  if (argc == 2) {
-    desired_exit_code = wcstoul(argv[1], nullptr, 0);
-  }
-
-  std::wstring cmd = argv[0];
-  base::LaunchOptions options = base::LaunchOptionsForTest();
-  base::Process setup_proc = base::LaunchProcess(cmd.c_str(), options);
-
-  if (setup_proc.IsValid()) {
-    setup_proc.Terminate(desired_exit_code, false);
-    return SBOX_TEST_SUCCEEDED;
-  }
-  // Note: GetLastError from CreateProcess returns 5, "ERROR_ACCESS_DENIED".
-  return SBOX_TEST_FAILED;
-}
-
-//------------------------------------------------------------------------------
-// Win8 Checks:
-// MITIGATION_DEP(_NO_ATL_THUNK)
-// MITIGATION_RELOCATE_IMAGE(_REQUIRED) - ASLR
-// MITIGATION_STRICT_HANDLE_CHECKS
-// >= Win8
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
-  if (!CheckWin8DepPolicy())
-    return SBOX_TEST_FIRST_ERROR;
-#endif
-
-  if (!CheckWin8AslrPolicy())
-    return SBOX_TEST_SECOND_ERROR;
-
-  if (!CheckWin8StrictHandlePolicy())
-    return SBOX_TEST_THIRD_ERROR;
-
-  return SBOX_TEST_SUCCEEDED;
-}
-
-TEST(ProcessMitigationsTest, CheckWin8) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // ASLR cannot be forced on start in debug builds.
-  constexpr sandbox::MitigationFlags kDebugDelayedMitigations =
-      MITIGATION_RELOCATE_IMAGE | MITIGATION_RELOCATE_IMAGE_REQUIRED;
-
-  sandbox::MitigationFlags mitigations =
-      MITIGATION_DEP | MITIGATION_DEP_NO_ATL_THUNK;
-#if defined(NDEBUG)
-  mitigations |= kDebugDelayedMitigations;
-#endif
-
-  EXPECT_EQ(policy->SetProcessMitigations(mitigations), SBOX_ALL_OK);
-
-  mitigations |= MITIGATION_STRICT_HANDLE_CHECKS;
-
-#if !defined(NDEBUG)
-  mitigations |= kDebugDelayedMitigations;
-#endif
-
-  EXPECT_EQ(policy->SetDelayedProcessMitigations(mitigations), SBOX_ALL_OK);
-
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8"));
-}
-
-//------------------------------------------------------------------------------
-// DEP (MITIGATION_DEP)
-// < Win8 x86
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t** argv) {
-  GetProcessDEPPolicyFunction get_process_dep_policy =
-      reinterpret_cast<GetProcessDEPPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
-  if (get_process_dep_policy) {
-    BOOL is_permanent = FALSE;
-    DWORD dep_flags = 0;
-
-    if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
-                                &is_permanent)) {
-      return SBOX_TEST_FIRST_ERROR;
-    }
-
-    if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent)
-      return SBOX_TEST_SECOND_ERROR;
-
-  } else {
-    NtQueryInformationProcessFunction query_information_process = NULL;
-    ResolveNTFunctionPtr("NtQueryInformationProcess",
-                         &query_information_process);
-    if (!query_information_process)
-      return SBOX_TEST_NOT_FOUND;
-
-    ULONG size = 0;
-    ULONG dep_flags = 0;
-    if (!SUCCEEDED(query_information_process(::GetCurrentProcess(),
-                                             ProcessExecuteFlags, &dep_flags,
-                                             sizeof(dep_flags), &size))) {
-      return SBOX_TEST_THIRD_ERROR;
-    }
-
-    static const int MEM_EXECUTE_OPTION_DISABLE = 2;
-    static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
-    dep_flags &= 0xff;
-
-    if (dep_flags !=
-        (MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT)) {
-      return SBOX_TEST_FOURTH_ERROR;
-    }
-  }
-
-  return SBOX_TEST_SUCCEEDED;
-}
-
-#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
-TEST(ProcessMitigationsTest, CheckDep) {
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DEP |
-                                          MITIGATION_DEP_NO_ATL_THUNK |
-                                          MITIGATION_SEHOP),
-            SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep"));
-}
-#endif
-
-//------------------------------------------------------------------------------
-// Win32k Lockdown (MITIGATION_WIN32K_DISABLE)
-// >= Win8
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-  if (!CheckWin8Win32CallPolicy())
-    return SBOX_TEST_FIRST_ERROR;
-  return SBOX_TEST_SUCCEEDED;
-}
-
-SBOX_TESTS_COMMAND int CheckWin8MonitorsRedirection(int argc, wchar_t** argv) {
-  std::map<HMONITOR, base::string16> monitors = EnumerateMonitors();
-  std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors();
-  if (monitors.size() != monitors_to_test.size())
-    return SBOX_TEST_FIRST_ERROR;
-
-  for (const auto& monitor : monitors) {
-    auto result = monitors_to_test.find(monitor.first);
-    if (result == monitors_to_test.end())
-      return SBOX_TEST_SECOND_ERROR;
-    if (result->second != monitor.second)
-      return SBOX_TEST_THIRD_ERROR;
-  }
-  return SBOX_TEST_SUCCEEDED;
-}
-
-SBOX_TESTS_COMMAND int CheckWin8MonitorInfo(int argc, wchar_t** argv) {
-  std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors();
-  MONITORINFO monitor_info = {};
-  MONITORINFOEXW monitor_info_exw = {};
-  MONITORINFOEXA monitor_info_exa = {};
-  HMONITOR valid_monitor = monitors_to_test.begin()->first;
-  std::wstring valid_device = monitors_to_test.begin()->second;
-  monitor_info.cbSize = sizeof(MONITORINFO);
-  if (!::GetMonitorInfoW(valid_monitor, &monitor_info))
-    return SBOX_TEST_FIRST_ERROR;
-  monitor_info.cbSize = sizeof(MONITORINFO);
-  if (!::GetMonitorInfoA(valid_monitor, &monitor_info))
-    return SBOX_TEST_SECOND_ERROR;
-  monitor_info_exw.cbSize = sizeof(MONITORINFOEXW);
-  if (!::GetMonitorInfoW(valid_monitor,
-                         reinterpret_cast<MONITORINFO*>(&monitor_info_exw)) ||
-      valid_device != monitor_info_exw.szDevice) {
-    return SBOX_TEST_THIRD_ERROR;
-  }
-  monitor_info_exa.cbSize = sizeof(MONITORINFOEXA);
-  if (!::GetMonitorInfoA(valid_monitor,
-                         reinterpret_cast<MONITORINFO*>(&monitor_info_exa)) ||
-      valid_device != base::ASCIIToUTF16(monitor_info_exa.szDevice)) {
-    return SBOX_TEST_FOURTH_ERROR;
-  }
-
-  // Invalid size checks.
-  monitor_info.cbSize = 0;
-  if (::GetMonitorInfoW(valid_monitor, &monitor_info))
-    return SBOX_TEST_FIFTH_ERROR;
-  monitor_info.cbSize = 0x10000;
-  if (::GetMonitorInfoW(valid_monitor, &monitor_info))
-    return SBOX_TEST_SIXTH_ERROR;
-
-  // Check that an invalid handle isn't accepted.
-  HMONITOR invalid_monitor = reinterpret_cast<HMONITOR>(-1);
-  monitor_info.cbSize = sizeof(MONITORINFO);
-  if (::GetMonitorInfoW(invalid_monitor, &monitor_info))
-    return SBOX_TEST_SEVENTH_ERROR;
-
-  return SBOX_TEST_SUCCEEDED;
-}
-
-bool RunTestsOnVideoOutputConfigure(uintptr_t monitor_index,
-                                    IOPMVideoOutput* video_output) {
-  OPM_CONFIGURE_PARAMETERS config_params = {};
-  OPM_SET_PROTECTION_LEVEL_PARAMETERS* protection_level =
-      reinterpret_cast<OPM_SET_PROTECTION_LEVEL_PARAMETERS*>(
-          config_params.abParameters);
-  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP;
-  protection_level->ulProtectionLevel = OPM_HDCP_ON;
-  config_params.guidSetting = OPM_SET_PROTECTION_LEVEL;
-  config_params.cbParametersSize = sizeof(OPM_SET_PROTECTION_LEVEL_PARAMETERS);
-  HRESULT hr = video_output->Configure(&config_params, 0, nullptr);
-  if (FAILED(hr))
-    return false;
-  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_DPCP;
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (FAILED(hr))
-    return false;
-  protection_level->ulProtectionLevel = OPM_HDCP_OFF;
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (FAILED(hr))
-    return false;
-  BYTE dummy_byte = 0;
-  hr = video_output->Configure(&config_params, 1, &dummy_byte);
-  if (SUCCEEDED(hr))
-    return false;
-  protection_level->ulProtectionType = 0xFFFFFFFF;
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (SUCCEEDED(hr))
-    return false;
-  // Invalid protection level test.
-  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP;
-  protection_level->ulProtectionLevel = OPM_HDCP_ON + 1;
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (SUCCEEDED(hr))
-    return false;
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (SUCCEEDED(hr))
-    return false;
-  config_params.guidSetting = OPM_SET_HDCP_SRM;
-  OPM_SET_HDCP_SRM_PARAMETERS* srm_parameters =
-      reinterpret_cast<OPM_SET_HDCP_SRM_PARAMETERS*>(
-          config_params.abParameters);
-  srm_parameters->ulSRMVersion = 1;
-  config_params.cbParametersSize = sizeof(OPM_SET_HDCP_SRM_PARAMETERS);
-  hr = video_output->Configure(&config_params, 0, nullptr);
-  if (SUCCEEDED(hr))
-    return false;
-  return true;
-}
-
-bool RunTestsOnVideoOutputFinishInitialization(uintptr_t monitor_index,
-                                               IOPMVideoOutput* video_output) {
-  OPM_ENCRYPTED_INITIALIZATION_PARAMETERS init_params = {};
-  memset(init_params.abEncryptedInitializationParameters, 'a' + monitor_index,
-         sizeof(init_params.abEncryptedInitializationParameters));
-  HRESULT hr = video_output->FinishInitialization(&init_params);
-  if (FAILED(hr))
-    return false;
-  memset(init_params.abEncryptedInitializationParameters, 'Z' + monitor_index,
-         sizeof(init_params.abEncryptedInitializationParameters));
-  hr = video_output->FinishInitialization(&init_params);
-  if (SUCCEEDED(hr))
-    return false;
-  return true;
-}
-
-bool RunTestsOnVideoOutputStartInitialization(uintptr_t monitor_index,
-                                              IOPMVideoOutput* video_output) {
-  OPM_RANDOM_NUMBER random_number = {};
-  BYTE* certificate = nullptr;
-  ULONG certificate_length = 0;
-
-  HRESULT hr = video_output->StartInitialization(&random_number, &certificate,
-                                                 &certificate_length);
-  if (FAILED(hr))
-    return false;
-
-  if (certificate_length != CalculateCertLength(monitor_index))
-    return false;
-
-  for (ULONG i = 0; i < certificate_length; ++i) {
-    if (certificate[i] != 'A' + monitor_index)
-      return false;
-  }
-
-  for (ULONG i = 0; i < sizeof(random_number.abRandomNumber); ++i) {
-    if (random_number.abRandomNumber[i] != '!' + monitor_index)
-      return false;
-  }
-
-  return true;
-}
-
-static bool SendSingleGetInfoRequest(uintptr_t monitor_index,
-                                     IOPMVideoOutput* video_output,
-                                     const GUID& request,
-                                     ULONG data_length,
-                                     void* data) {
-  OPM_GET_INFO_PARAMETERS params = {};
-  OPM_REQUESTED_INFORMATION requested_information = {};
-  BYTE* requested_information_ptr =
-      reinterpret_cast<BYTE*>(&requested_information);
-  params.guidInformation = request;
-  params.cbParametersSize = data_length;
-  memcpy(params.abParameters, data, data_length);
-  HRESULT hr = video_output->GetInformation(&params, &requested_information);
-  if (FAILED(hr))
-    return false;
-  for (size_t i = 0; i < sizeof(OPM_REQUESTED_INFORMATION); ++i) {
-    if (requested_information_ptr[i] != '0' + monitor_index)
-      return false;
-  }
-  return true;
-}
-
-bool RunTestsOnVideoOutputGetInformation(uintptr_t monitor_index,
-                                         IOPMVideoOutput* video_output) {
-  ULONG dummy = 0;
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_CONNECTOR_TYPE, 0, nullptr)) {
-    return false;
-  }
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_SUPPORTED_PROTECTION_TYPES, 0,
-                                nullptr)) {
-    return false;
-  }
-  // These should fail due to invalid parameter sizes.
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_CONNECTOR_TYPE, sizeof(dummy), &dummy)) {
-    return false;
-  }
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_SUPPORTED_PROTECTION_TYPES,
-                               sizeof(dummy), &dummy)) {
-    return false;
-  }
-  ULONG protection_type = OPM_PROTECTION_TYPE_HDCP;
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_ACTUAL_PROTECTION_LEVEL,
-                                sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  protection_type = OPM_PROTECTION_TYPE_DPCP;
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_ACTUAL_PROTECTION_LEVEL,
-                                sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  // These should fail as unsupported or invalid parameters.
-  protection_type = OPM_PROTECTION_TYPE_ACP;
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_ACTUAL_PROTECTION_LEVEL,
-                               sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_ACTUAL_PROTECTION_LEVEL, 0, nullptr)) {
-    return false;
-  }
-  protection_type = OPM_PROTECTION_TYPE_HDCP;
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_VIRTUAL_PROTECTION_LEVEL,
-                                sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  protection_type = OPM_PROTECTION_TYPE_DPCP;
-  if (!SendSingleGetInfoRequest(monitor_index, video_output,
-                                OPM_GET_VIRTUAL_PROTECTION_LEVEL,
-                                sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  // These should fail as unsupported or invalid parameters.
-  protection_type = OPM_PROTECTION_TYPE_ACP;
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_VIRTUAL_PROTECTION_LEVEL,
-                               sizeof(protection_type), &protection_type)) {
-    return false;
-  }
-  if (SendSingleGetInfoRequest(monitor_index, video_output,
-                               OPM_GET_VIRTUAL_PROTECTION_LEVEL, 0, nullptr)) {
-    return false;
-  }
-  // This should fail with unsupported request.
-  if (SendSingleGetInfoRequest(monitor_index, video_output, OPM_GET_CODEC_INFO,
-                               0, nullptr)) {
-    return false;
-  }
-  return true;
-}
-
-int RunTestsOnVideoOutput(uintptr_t monitor_index,
-                          IOPMVideoOutput* video_output) {
-  if (!RunTestsOnVideoOutputStartInitialization(monitor_index, video_output))
-    return SBOX_TEST_FIRST_ERROR;
-
-  if (!RunTestsOnVideoOutputFinishInitialization(monitor_index, video_output))
-    return SBOX_TEST_SECOND_ERROR;
-
-  if (!RunTestsOnVideoOutputConfigure(monitor_index, video_output))
-    return SBOX_TEST_THIRD_ERROR;
-
-  if (!RunTestsOnVideoOutputGetInformation(monitor_index, video_output))
-    return SBOX_TEST_FOURTH_ERROR;
-
-  return SBOX_TEST_SUCCEEDED;
-}
-
-SBOX_TESTS_COMMAND int CheckWin8OPMApis(int argc, wchar_t** argv) {
-  std::map<HMONITOR, base::string16> monitors = GetTestMonitors();
-  for (const auto& monitor : monitors) {
-    ULONG output_count = 0;
-    IOPMVideoOutput** outputs = nullptr;
-    uintptr_t monitor_index = reinterpret_cast<uintptr_t>(monitor.first) & 0xF;
-    HRESULT hr = OPMGetVideoOutputsFromHMONITOR(
-        monitor.first, OPM_VOS_OPM_SEMANTICS, &output_count, &outputs);
-    if (monitor_index > 4) {
-      // These should fail because the certificate is too large.
-      if (SUCCEEDED(hr))
-        return SBOX_TEST_FIRST_ERROR;
-      continue;
-    }
-    if (FAILED(hr))
-      return SBOX_TEST_SECOND_ERROR;
-    if (output_count != monitor_index - 1)
-      return SBOX_TEST_THIRD_ERROR;
-    for (ULONG output_index = 0; output_index < output_count; ++output_index) {
-      int result = RunTestsOnVideoOutput(monitor_index, outputs[output_index]);
-      outputs[output_index]->Release();
-      if (result != SBOX_TEST_SUCCEEDED)
-        return result;
-    }
-    ::CoTaskMemFree(outputs);
-  }
-  return SBOX_TEST_SUCCEEDED;
-}
-
-// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on
-// the target process causes the launch to fail in process initialization.
-// The test process itself links against user32/gdi32.
-TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownFailure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
-            SBOX_ALL_OK);
-  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
-}
-
-// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation
-// along with the policy to fake user32 and gdi32 initialization successfully
-// launches the target process.
-// The test process itself links against user32/gdi32.
-TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownSuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-  ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
-      FunctionOverrideForTest);
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
-            SBOX_ALL_OK);
-  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
-                            sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL),
-            sandbox::SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
-  EXPECT_NE(SBOX_TEST_SUCCEEDED,
-            runner.RunTest(L"CheckWin8MonitorsRedirection"));
-  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo"));
-  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis"));
-}
-
-// This test validates the even though we're running under win32k lockdown
-// we can use the IPC redirection to enumerate the list of monitors.
-TEST(ProcessMitigationsTest, CheckWin8Win32KRedirection) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-  ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
-      FunctionOverrideForTest);
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
-            SBOX_ALL_OK);
-  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
-                            sandbox::TargetPolicy::IMPLEMENT_OPM_APIS, NULL),
-            sandbox::SBOX_ALL_OK);
-  policy->SetEnableOPMRedirection();
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
-            runner.RunTest(L"CheckWin8MonitorsRedirection"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo"));
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis"));
-}
-
-//------------------------------------------------------------------------------
-// Disable extension points (MITIGATION_EXTENSION_POINT_DISABLE).
-// >= Win8
-//------------------------------------------------------------------------------
-SBOX_TESTS_COMMAND int CheckWin8ExtensionPointSetting(int argc,
-                                                      wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-  if (!CheckWin8ExtensionPointPolicy())
-    return SBOX_TEST_FIRST_ERROR;
-  return SBOX_TEST_SUCCEEDED;
-}
-
-// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
-// mitigation enables the setting on a process.
-TEST(ProcessMitigationsTest, CheckWin8ExtensionPointPolicySuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_EXTENSION_POINT_DISABLE),
-            SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
-            runner.RunTest(L"CheckWin8ExtensionPointSetting"));
-}
-
-// This test validates that a "legitimate" global hook CAN be set on the
-// sandboxed proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE
-// mitigation is not set.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest,
-     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Success) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  // (is_success_test, global_hook)
-  TestWin8ExtensionPointHookWrapper(true, true);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
-// mitigation prevents a global hook on WinProc.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest,
-     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Failure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  // (is_success_test, global_hook)
-  TestWin8ExtensionPointHookWrapper(false, true);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-// This test validates that a "legitimate" hook CAN be set on the sandboxed
-// proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Success) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  // (is_success_test, global_hook)
-  TestWin8ExtensionPointHookWrapper(true, false);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-// *** Important: MITIGATION_EXTENSION_POINT_DISABLE does NOT prevent
-// hooks targetted at a specific thread id.  It only prevents
-// global hooks.  So this test does NOT actually expect the hook
-// to fail (see TestWin8ExtensionPointHookWrapper function) even
-// with the mitigation on.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Failure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  // (is_success_test, global_hook)
-  TestWin8ExtensionPointHookWrapper(false, false);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-// This test validates that an AppInit Dll CAN be added to a target
-// WinProc if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
-//
-// MANUAL testing only.
-// Must run this test as admin/elevated.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Success) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  TestWin8ExtensionPointAppInitWrapper(true);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
-// mitigation prevents the loading of any AppInit Dll into WinProc.
-//
-// MANUAL testing only.
-// Must run this test as admin/elevated.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Failure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
-    return;
-
-  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
-  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
-
-  TestWin8ExtensionPointAppInitWrapper(false);
-
-  EXPECT_TRUE(::ReleaseMutex(mutex));
-  EXPECT_TRUE(::CloseHandle(mutex));
-}
-
-//------------------------------------------------------------------------------
-// Disable non-system font loads (MITIGATION_NONSYSTEM_FONT_DISABLE)
-// >= Win10
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckWin10FontLockDown(int argc, wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-  if (!CheckWin10FontPolicy())
-    return SBOX_TEST_FIRST_ERROR;
-  return SBOX_TEST_SUCCEEDED;
-}
-
-SBOX_TESTS_COMMAND int CheckWin10FontLoad(int argc, wchar_t** argv) {
-  if (argc < 1)
-    return SBOX_TEST_INVALID_PARAMETER;
-
-  HMODULE gdi_module = ::LoadLibraryW(L"gdi32.dll");
-  if (!gdi_module)
-    return SBOX_TEST_NOT_FOUND;
-
-  AddFontMemResourceExFunction add_font_mem_resource =
-      reinterpret_cast<AddFontMemResourceExFunction>(
-          ::GetProcAddress(gdi_module, "AddFontMemResourceEx"));
-
-  RemoveFontMemResourceExFunction rem_font_mem_resource =
-      reinterpret_cast<RemoveFontMemResourceExFunction>(
-          ::GetProcAddress(gdi_module, "RemoveFontMemResourceEx"));
-
-  if (!add_font_mem_resource || !rem_font_mem_resource)
-    return SBOX_TEST_NOT_FOUND;
-
-  // Open font file passed in as an argument.
-  base::File file(base::FilePath(argv[0]),
-                  base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!file.IsValid())
-    // Failed to open the font file passed in.
-    return SBOX_TEST_NOT_FOUND;
-
-  std::vector<char> font_data;
-  int64_t len = file.GetLength();
-  if (len < 0)
-    return SBOX_TEST_NOT_FOUND;
-  font_data.resize(len);
-
-  int read = file.Read(0, &font_data[0], len);
-  file.Close();
-
-  if (read != len)
-    return SBOX_TEST_NOT_FOUND;
-
-  DWORD font_count = 0;
-  HANDLE font_handle = add_font_mem_resource(
-      &font_data[0], static_cast<DWORD>(font_data.size()), NULL, &font_count);
-
-  if (font_handle) {
-    rem_font_mem_resource(font_handle);
-    return SBOX_TEST_SUCCEEDED;
-  }
-
-  return SBOX_TEST_FAILED;
-}
-
-// This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE
-// mitigation enables the setting on a process.
-TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownPolicySuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE),
-            SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin10FontLockDown"));
-}
-
-// This test validates that we can load a non-system font
-// if the MITIGATION_NON_SYSTEM_FONTS_DISABLE
-// mitigation is NOT set.
-TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadSuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10)
-    return;
-
-  base::FilePath font_path;
-  EXPECT_TRUE(base::PathService::Get(base::DIR_WINDOWS_FONTS, &font_path));
-  // Arial font should always be available
-  font_path = font_path.Append(L"arial.ttf");
-
-  TestRunner runner;
-  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
-                               font_path.value().c_str()));
-
-  std::wstring test_command = L"CheckWin10FontLoad \"";
-  test_command += font_path.value().c_str();
-  test_command += L"\"";
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
-}
-
-// This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE
-// mitigation prevents the loading of a non-system font.
-TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadFailure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10)
-    return;
-
-  base::FilePath font_path;
-  EXPECT_TRUE(base::PathService::Get(base::DIR_WINDOWS_FONTS, &font_path));
-  // Arial font should always be available
-  font_path = font_path.Append(L"arial.ttf");
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
-                               font_path.value().c_str()));
-
-  // Turn on the non-system font disable mitigation.
-  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE),
-            SBOX_ALL_OK);
-
-  std::wstring test_command = L"CheckWin10FontLoad \"";
-  test_command += font_path.value().c_str();
-  test_command += L"\"";
-
-  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(test_command.c_str()));
-}
-
-//------------------------------------------------------------------------------
-// Disable image load from remote devices (MITIGATION_IMAGE_LOAD_NO_REMOTE).
-// >= Win10_TH2
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckWin10ImageLoadNoRemote(int argc, wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-  if (!CheckWin10ImageLoadNoRemotePolicy())
-    return SBOX_TEST_FIRST_ERROR;
-  return SBOX_TEST_SUCCEEDED;
-}
-
-// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE
-// mitigation enables the setting on a process.
-TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoRemotePolicySuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(
-      policy->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_REMOTE),
-      SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
-            runner.RunTest(L"CheckWin10ImageLoadNoRemote"));
-}
-
-// This test validates that we CAN create a new process from
-// a remote UNC device, if the MITIGATION_IMAGE_LOAD_NO_REMOTE
-// mitigation is NOT set.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteSuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestWin10ImageLoadRemote(true);
-}
-
-// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE
-// mitigation prevents creating a new process from a remote
-// UNC device.
-//
-// MANUAL testing only.
-TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteFailure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestWin10ImageLoadRemote(false);
-}
-
-//------------------------------------------------------------------------------
-// Disable image load when "mandatory low label" (integrity level).
-// (MITIGATION_IMAGE_LOAD_NO_LOW_LABEL)
-// >= Win10_TH2
-//------------------------------------------------------------------------------
-
-SBOX_TESTS_COMMAND int CheckWin10ImageLoadNoLowLabel(int argc, wchar_t** argv) {
-  get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
-          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
-  if (!get_process_mitigation_policy)
-    return SBOX_TEST_NOT_FOUND;
-
-  if (!CheckWin10ImageLoadNoLowLabelPolicy())
-    return SBOX_TEST_FIRST_ERROR;
-  return SBOX_TEST_SUCCEEDED;
-}
-
-// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
-// mitigation enables the setting on a process.
-TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelPolicySuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  EXPECT_EQ(
-      policy->SetDelayedProcessMitigations(MITIGATION_IMAGE_LOAD_NO_LOW_LABEL),
-      SBOX_ALL_OK);
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
-            runner.RunTest(L"CheckWin10ImageLoadNoLowLabel"));
-}
-
-// This test validates that we CAN create a new process with
-// low mandatory label (IL), if the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
-// mitigation is NOT set.
-TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelSuccess) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestWin10ImageLoadLowLabel(true);
-}
-
-// This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
-// mitigation prevents creating a new process with low mandatory label (IL).
-TEST(ProcessMitigationsTest, CheckWin10ImageLoadNoLowLabelFailure) {
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
-    return;
-
-  TestWin10ImageLoadLowLabel(false);
-}
-
-//------------------------------------------------------------------------------
-// Disable child process creation.
-// - JobLevel <= JOB_LIMITED_USER (on < WIN10_TH2).
-// - JobLevel <= JOB_LIMITED_USER which also triggers setting
-//   PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY to
-//   PROCESS_CREATION_CHILD_PROCESS_RESTRICTED in
-//   BrokerServicesBase::SpawnTarget (on >= WIN10_TH2).
-//------------------------------------------------------------------------------
-
-// This test validates that we can spawn a child process if
-// MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation is
-// not set.
-TEST(ProcessMitigationsTest, CheckChildProcessSuccess) {
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // Set a policy that would normally allow for process creation.
-  policy->SetJobLevel(JOB_INTERACTIVE, 0);
-  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
-  runner.SetDisableCsrss(false);
-
-  base::FilePath cmd;
-  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
-  cmd = cmd.Append(L"calc.exe");
-
-  std::wstring test_command = L"TestChildProcess ";
-  test_command += cmd.value().c_str();
-
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
-}
-
-// This test validates that setting the
-// MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation prevents
-// the spawning of child processes.
-TEST(ProcessMitigationsTest, CheckChildProcessFailure) {
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // Now set the job level to be <= JOB_LIMITED_USER
-  // and ensure we can no longer create a child process.
-  policy->SetJobLevel(JOB_LIMITED_USER, 0);
-  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
-  runner.SetDisableCsrss(false);
-
-  base::FilePath cmd;
-  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
-  cmd = cmd.Append(L"calc.exe");
-
-  std::wstring test_command = L"TestChildProcess ";
-  test_command += cmd.value().c_str();
-
-  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(test_command.c_str()));
-}
-
-// This test validates that when the sandboxed target within a job spawns a
-// child process and the target process exits abnormally, the broker correctly
-// handles the JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS message.
-// Because this involves spawning a child process from the target process and is
-// very similar to the above CheckChildProcess* tests, this test is here rather
-// than elsewhere closer to the other Job tests.
-TEST(ProcessMitigationsTest, CheckChildProcessAbnormalExit) {
-  TestRunner runner;
-  sandbox::TargetPolicy* policy = runner.GetPolicy();
-
-  // Set a policy that would normally allow for process creation.
-  policy->SetJobLevel(JOB_INTERACTIVE, 0);
-  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
-  runner.SetDisableCsrss(false);
-
-  base::FilePath cmd;
-  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
-  cmd = cmd.Append(L"calc.exe");
-
-  std::wstring test_command(base::StringPrintf(L"TestChildProcess %ls 0x%08X",
-                                               cmd.value().c_str(),
-                                               STATUS_ACCESS_VIOLATION));
-
-  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc
new file mode 100644
index 0000000..e41ccd4
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -0,0 +1,677 @@
+// Copyright 2011 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 "sandbox/win/src/process_mitigations.h"
+
+#include <windows.h>
+
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_native_library.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Internal Defines & Functions
+//------------------------------------------------------------------------------
+
+// API defined in winbase.h.
+using GetProcessDEPPolicyFunction = decltype(&GetProcessDEPPolicy);
+
+// API defined in processthreadsapi.h.
+using GetProcessMitigationPolicyFunction =
+    decltype(&GetProcessMitigationPolicy);
+GetProcessMitigationPolicyFunction get_process_mitigation_policy;
+
+// APIs defined in wingdi.h.
+using AddFontMemResourceExFunction = decltype(&AddFontMemResourceEx);
+using RemoveFontMemResourceExFunction = decltype(&RemoveFontMemResourceEx);
+
+//------------------------------------------------------------------------------
+// NonSystemFont test helper function.
+//
+// 1. Pick font file and set up sandbox to allow read access to it.
+// 2. Trigger test child process (with or without mitigation enabled).
+//------------------------------------------------------------------------------
+void TestWin10NonSystemFont(bool is_success_test) {
+  base::FilePath font_path;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_WINDOWS_FONTS, &font_path));
+  // Arial font should always be available
+  font_path = font_path.Append(L"arial.ttf");
+
+  sandbox::TestRunner runner;
+  EXPECT_TRUE(runner.AddFsRule(sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+                               font_path.value().c_str()));
+
+  if (!is_success_test) {
+    sandbox::TargetPolicy* policy = runner.GetPolicy();
+    // Turn on the non-system font disable mitigation.
+    EXPECT_EQ(policy->SetProcessMitigations(
+                  sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE),
+              sandbox::SBOX_ALL_OK);
+  }
+
+  base::string16 test_command = L"CheckWin10FontLoad \"";
+  test_command += font_path.value().c_str();
+  test_command += L"\"";
+
+  EXPECT_EQ((is_success_test ? sandbox::SBOX_TEST_SUCCEEDED
+                             : sandbox::SBOX_TEST_FAILED),
+            runner.RunTest(test_command.c_str()));
+}
+
+}  // namespace
+
+namespace sandbox {
+
+//------------------------------------------------------------------------------
+// Exported functions called by child test processes.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Common test function for checking that a policy was enabled.
+// - Use enum TestPolicy defined in integration_tests_common.h to specify which
+//   policy to check - passed as arg1.
+//------------------------------------------------------------------------------
+SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) {
+  if (argc < 1)
+    return SBOX_TEST_INVALID_PARAMETER;
+  int test = ::_wtoi(argv[0]);
+  if (!test)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  get_process_mitigation_policy =
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
+  if (!get_process_mitigation_policy)
+    return SBOX_TEST_NOT_FOUND;
+
+  switch (test) {
+    //--------------------------------------------------
+    // MITIGATION_DEP
+    // MITIGATION_DEP_NO_ATL_THUNK
+    //--------------------------------------------------
+    case (TESTPOLICY_DEP): {
+#if !defined(_WIN64)
+      // DEP - always enabled on 64-bit.
+      PROCESS_MITIGATION_DEP_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessDEPPolicy, &policy,
+                                         sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.Enable || !policy.Permanent)
+        return SBOX_TEST_FAILED;
+#endif  // !defined(_WIN64)
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_RELOCATE_IMAGE
+    // MITIGATION_RELOCATE_IMAGE_REQUIRED
+    //--------------------------------------------------
+    case (TESTPOLICY_ASLR): {
+      PROCESS_MITIGATION_ASLR_POLICY policy2 = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessASLRPolicy, &policy2,
+                                         sizeof(policy2))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy2.EnableForceRelocateImages || !policy2.DisallowStrippedImages)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_STRICT_HANDLE_CHECKS
+    //--------------------------------------------------
+    case (TESTPOLICY_STRICTHANDLE): {
+      PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy3 = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessStrictHandleCheckPolicy,
+                                         &policy3, sizeof(policy3))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy3.RaiseExceptionOnInvalidHandleReference ||
+          !policy3.HandleExceptionsPermanentlyEnabled) {
+        return SBOX_TEST_FAILED;
+      }
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_WIN32K_DISABLE
+    //--------------------------------------------------
+    case (TESTPOLICY_WIN32K): {
+      PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessSystemCallDisablePolicy,
+                                         &policy, sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.DisallowWin32kSystemCalls)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_EXTENSION_POINT_DISABLE
+    //--------------------------------------------------
+    case (TESTPOLICY_EXTENSIONPOINT): {
+      PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessExtensionPointDisablePolicy,
+                                         &policy, sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.DisableExtensionPoints)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_NONSYSTEM_FONT_DISABLE
+    //--------------------------------------------------
+    case (TESTPOLICY_NONSYSFONT): {
+      PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessFontDisablePolicy, &policy,
+                                         sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.DisableNonSystemFonts)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_IMAGE_LOAD_NO_REMOTE
+    //--------------------------------------------------
+    case (TESTPOLICY_LOADNOREMOTE): {
+      PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessImageLoadPolicy, &policy,
+                                         sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.NoRemoteImages)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    //--------------------------------------------------
+    // MITIGATION_IMAGE_LOAD_NO_LOW_LABEL
+    //--------------------------------------------------
+    case (TESTPOLICY_LOADNOLOW): {
+      PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
+      if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                         ProcessImageLoadPolicy, &policy,
+                                         sizeof(policy))) {
+        return SBOX_TEST_NOT_FOUND;
+      }
+      if (!policy.NoLowMandatoryLabelImages)
+        return SBOX_TEST_FAILED;
+
+      break;
+    }
+    default:
+      return SBOX_TEST_INVALID_PARAMETER;
+  }
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t** argv) {
+  GetProcessDEPPolicyFunction get_process_dep_policy =
+      reinterpret_cast<GetProcessDEPPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
+  if (get_process_dep_policy) {
+    BOOL is_permanent = FALSE;
+    DWORD dep_flags = 0;
+
+    if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
+                                &is_permanent)) {
+      return SBOX_TEST_FIRST_ERROR;
+    }
+
+    if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent)
+      return SBOX_TEST_SECOND_ERROR;
+
+  } else {
+    NtQueryInformationProcessFunction query_information_process = NULL;
+    ResolveNTFunctionPtr("NtQueryInformationProcess",
+                         &query_information_process);
+    if (!query_information_process)
+      return SBOX_TEST_NOT_FOUND;
+
+    ULONG size = 0;
+    ULONG dep_flags = 0;
+    if (!SUCCEEDED(query_information_process(::GetCurrentProcess(),
+                                             ProcessExecuteFlags, &dep_flags,
+                                             sizeof(dep_flags), &size))) {
+      return SBOX_TEST_THIRD_ERROR;
+    }
+
+    static const int MEM_EXECUTE_OPTION_DISABLE = 2;
+    static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
+    dep_flags &= 0xff;
+
+    if (dep_flags !=
+        (MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT)) {
+      return SBOX_TEST_FOURTH_ERROR;
+    }
+  }
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// ForceMsSigned tests:
+// Try to load the DLL given in arg1.
+SBOX_TESTS_COMMAND int TestDllLoad(int argc, wchar_t** argv) {
+  if (argc < 1 || argv[0] == nullptr)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  base::string16 dll = argv[0];
+  base::ScopedNativeLibrary test_dll((base::FilePath(dll)));
+  if (test_dll.is_valid())
+    return SBOX_TEST_SUCCEEDED;
+
+  // Note: GetLastError() does not get an accurate failure code
+  //       at this point.
+  return SBOX_TEST_FAILED;
+}
+
+// This test attempts a non-system font load.
+//
+// 1) Load gdi32.dll for required font APIs.
+// 2) Load file contents of font file passed in arg1 into memory.
+// 3) Call API to try loading a non-system font.
+//
+// Arg1: Full path to font file to try loading.
+SBOX_TESTS_COMMAND int CheckWin10FontLoad(int argc, wchar_t** argv) {
+  if (argc < 1)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  HMODULE gdi_module = ::LoadLibraryW(L"gdi32.dll");
+  if (!gdi_module)
+    return SBOX_TEST_NOT_FOUND;
+
+  AddFontMemResourceExFunction add_font_mem_resource =
+      reinterpret_cast<AddFontMemResourceExFunction>(
+          ::GetProcAddress(gdi_module, "AddFontMemResourceEx"));
+
+  RemoveFontMemResourceExFunction rem_font_mem_resource =
+      reinterpret_cast<RemoveFontMemResourceExFunction>(
+          ::GetProcAddress(gdi_module, "RemoveFontMemResourceEx"));
+
+  if (!add_font_mem_resource || !rem_font_mem_resource)
+    return SBOX_TEST_NOT_FOUND;
+
+  // Open font file passed in as an argument.
+  base::File file(base::FilePath(argv[0]),
+                  base::File::FLAG_OPEN | base::File::FLAG_READ);
+  if (!file.IsValid())
+    // Failed to open the font file passed in.
+    return SBOX_TEST_NOT_FOUND;
+
+  std::vector<char> font_data;
+  int64_t len = file.GetLength();
+  if (len < 0)
+    return SBOX_TEST_NOT_FOUND;
+  font_data.resize(len);
+
+  int read = file.Read(0, &font_data[0], len);
+  file.Close();
+
+  if (read != len)
+    return SBOX_TEST_NOT_FOUND;
+
+  DWORD font_count = 0;
+  HANDLE font_handle = add_font_mem_resource(
+      &font_data[0], static_cast<DWORD>(font_data.size()), NULL, &font_count);
+
+  if (font_handle) {
+    rem_font_mem_resource(font_handle);
+    return SBOX_TEST_SUCCEEDED;
+  }
+
+  return SBOX_TEST_FAILED;
+}
+
+// Common helper test for CreateProcess.
+// Arg1: The process commandline to create.
+// Arg2: Will process end on its own:
+//  - "true" for a process expected to finish on its own (wait for it).
+//  - "false" for a process that will require terminating.
+// Arg3: [OPTIONAL] Expected or forced exit code:
+//  - If arg2 is "true", this is the expected exit code (default 0).
+//  - If arg2 is "false", terminate the process with this exit code (default 0).
+//
+// ***Make sure you've enabled basic process creation in the
+// test sandbox settings via:
+// sandbox::TargetPolicy::SetJobLevel(),
+// sandbox::TargetPolicy::SetTokenLevel(),
+// and TestRunner::SetDisableCsrss().
+SBOX_TESTS_COMMAND int TestChildProcess(int argc, wchar_t** argv) {
+  if (argc < 2 || argc > 3)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  bool process_finishes = true;
+  base::string16 arg2 = argv[1];
+  if (arg2.compare(L"false") == 0)
+    process_finishes = false;
+
+  int desired_exit_code = 0;
+  if (argc == 3) {
+    desired_exit_code = wcstoul(argv[2], nullptr, 0);
+  }
+
+  base::string16 cmd = argv[0];
+  base::LaunchOptions options = base::LaunchOptionsForTest();
+  base::Process setup_proc = base::LaunchProcess(cmd.c_str(), options);
+
+  if (setup_proc.IsValid()) {
+    if (process_finishes) {
+      // Wait for process exit and compare exit code.
+      int exit_code = 1;
+      if (!setup_proc.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+                                             &exit_code)) {
+        // Unexpected failure.
+        setup_proc.Terminate(0, false);
+        return SBOX_TEST_TIMED_OUT;
+      }
+      if (exit_code != desired_exit_code)
+        return SBOX_TEST_FAILED;
+      return SBOX_TEST_SUCCEEDED;
+    } else {
+      // Terminate process with requested exit code.
+      setup_proc.Terminate(desired_exit_code, false);
+      return SBOX_TEST_SUCCEEDED;
+    }
+  }
+  // Process failed to be created.
+  // Note: GetLastError from CreateProcess returns 5, "ERROR_ACCESS_DENIED".
+  return SBOX_TEST_FAILED;
+}
+
+//------------------------------------------------------------------------------
+// Exported Mitigation Tests
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// DEP (MITIGATION_DEP and MITIGATION_DEP_NO_ATL_THUNK)
+// Win7 x86
+//------------------------------------------------------------------------------
+
+#if !defined(_WIN64)
+// DEP is always enabled on 64-bit.  Only test on x86.
+TEST(ProcessMitigationsTest, CheckDepWin7) {
+  if (base::win::GetVersion() > base::win::VERSION_WIN7)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DEP |
+                                          MITIGATION_DEP_NO_ATL_THUNK |
+                                          MITIGATION_SEHOP),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep"));
+}
+#endif  // !defined(_WIN64)
+
+//------------------------------------------------------------------------------
+// DEP (MITIGATION_DEP and MITIGATION_DEP_NO_ATL_THUNK)
+// >= Win8 x86
+//------------------------------------------------------------------------------
+
+#if !defined(_WIN64)
+// DEP is always enabled on 64-bit.  Only test on x86.
+
+// This test validates that setting the MITIGATION_DEP*
+// mitigations enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckDepWin8PolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_DEP);
+
+  //---------------------------------
+  // 1) Test setting pre-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DEP |
+                                          MITIGATION_DEP_NO_ATL_THUNK),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+  //---------------------------------
+  // 2) Test setting post-startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
+
+  EXPECT_EQ(policy2->SetDelayedProcessMitigations(MITIGATION_DEP |
+                                                  MITIGATION_DEP_NO_ATL_THUNK),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
+
+#endif  // !defined(_WIN64)
+
+//------------------------------------------------------------------------------
+// ASLR
+// - MITIGATION_RELOCATE_IMAGE
+// - MITIGATION_RELOCATE_IMAGE_REQUIRED
+// - MITIGATION_BOTTOM_UP_ASLR
+// - MITIGATION_HIGH_ENTROPY_ASLR
+// >= Win8
+//------------------------------------------------------------------------------
+
+TEST(ProcessMitigationsTest, CheckWin8AslrPolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_ASLR);
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+//---------------------------------
+// 1) Test setting pre-startup.
+//    **Can only set ASLR pre-startup in release build.
+//---------------------------------
+#if defined(NDEBUG)
+  EXPECT_EQ(policy->SetProcessMitigations(
+                MITIGATION_RELOCATE_IMAGE | MITIGATION_RELOCATE_IMAGE_REQUIRED |
+                MITIGATION_BOTTOM_UP_ASLR | MITIGATION_HIGH_ENTROPY_ASLR),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+//---------------------------------
+// 2) Test setting post-startup.
+//    **Bottom up and high entropy can only be set pre-startup.
+//    **Can only set ASLR post-startup in debug build.
+//---------------------------------
+#else
+  EXPECT_EQ(policy->SetDelayedProcessMitigations(
+                MITIGATION_RELOCATE_IMAGE | MITIGATION_RELOCATE_IMAGE_REQUIRED),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+#endif  // !defined(NDEBUG)
+}
+
+//------------------------------------------------------------------------------
+//  Strict handle checks (MITIGATION_STRICT_HANDLE_CHECKS)
+// >= Win8
+//------------------------------------------------------------------------------
+
+TEST(ProcessMitigationsTest, CheckWin8StrictHandlePolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_STRICTHANDLE);
+
+  //---------------------------------
+  // 1) Test setting post-startup.
+  // ** Can only be set post-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(
+      policy->SetDelayedProcessMitigations(MITIGATION_STRICT_HANDLE_CHECKS),
+      SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+}
+
+//------------------------------------------------------------------------------
+// Disable non-system font loads (MITIGATION_NONSYSTEM_FONT_DISABLE)
+// >= Win10
+//------------------------------------------------------------------------------
+
+// This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE
+// mitigation enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownPolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10)
+    return;
+
+  base::string16 test_command = L"CheckPolicy ";
+  test_command += std::to_wstring(TESTPOLICY_NONSYSFONT);
+
+  //---------------------------------
+  // 1) Test setting pre-startup.
+  //---------------------------------
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+
+  //---------------------------------
+  // 2) Test setting post-startup.
+  //---------------------------------
+  TestRunner runner2;
+  sandbox::TargetPolicy* policy2 = runner2.GetPolicy();
+
+  EXPECT_EQ(
+      policy2->SetDelayedProcessMitigations(MITIGATION_NONSYSTEM_FONT_DISABLE),
+      SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner2.RunTest(test_command.c_str()));
+}
+
+// This test validates that we can load a non-system font if the
+// MITIGATION_NON_SYSTEM_FONTS_DISABLE mitigation is NOT set.
+TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10)
+    return;
+
+  TestWin10NonSystemFont(true);
+}
+
+// This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE
+// mitigation prevents the loading of a non-system font.
+TEST(ProcessMitigationsTest, CheckWin10NonSystemFontLockDownLoadFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10)
+    return;
+
+  TestWin10NonSystemFont(false);
+}
+
+//------------------------------------------------------------------------------
+// Disable child process creation.
+// - JobLevel <= JOB_LIMITED_USER (on < WIN10_TH2).
+// - JobLevel <= JOB_LIMITED_USER which also triggers setting
+//   PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY to
+//   PROCESS_CREATION_CHILD_PROCESS_RESTRICTED in
+//   BrokerServicesBase::SpawnTarget (on >= WIN10_TH2).
+//------------------------------------------------------------------------------
+
+// This test validates that we can spawn a child process if
+// MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation is
+// not set.
+TEST(ProcessMitigationsTest, CheckChildProcessSuccess) {
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Set a policy that would normally allow for process creation.
+  policy->SetJobLevel(JOB_INTERACTIVE, 0);
+  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+  runner.SetDisableCsrss(false);
+
+  base::FilePath cmd;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
+  cmd = cmd.Append(L"calc.exe");
+
+  base::string16 test_command = L"TestChildProcess \"";
+  test_command += cmd.value().c_str();
+  test_command += L"\" false";
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+}
+
+// This test validates that setting the
+// MITIGATION_CHILD_PROCESS_CREATION_RESTRICTED mitigation prevents
+// the spawning of child processes.
+TEST(ProcessMitigationsTest, CheckChildProcessFailure) {
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Now set the job level to be <= JOB_LIMITED_USER
+  // and ensure we can no longer create a child process.
+  policy->SetJobLevel(JOB_LIMITED_USER, 0);
+  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+  runner.SetDisableCsrss(false);
+
+  base::FilePath cmd;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
+  cmd = cmd.Append(L"calc.exe");
+
+  base::string16 test_command = L"TestChildProcess \"";
+  test_command += cmd.value().c_str();
+  test_command += L"\" false";
+
+  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(test_command.c_str()));
+}
+
+// This test validates that when the sandboxed target within a job spawns a
+// child process and the target process exits abnormally, the broker correctly
+// handles the JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS message.
+// Because this involves spawning a child process from the target process and is
+// very similar to the above CheckChildProcess* tests, this test is here rather
+// than elsewhere closer to the other Job tests.
+TEST(ProcessMitigationsTest, CheckChildProcessAbnormalExit) {
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Set a policy that would normally allow for process creation.
+  policy->SetJobLevel(JOB_INTERACTIVE, 0);
+  policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+  runner.SetDisableCsrss(false);
+
+  base::FilePath cmd;
+  EXPECT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &cmd));
+  cmd = cmd.Append(L"calc.exe");
+
+  base::string16 test_command = L"TestChildProcess \"";
+  test_command += cmd.value().c_str();
+  test_command += L"\" false ";
+  test_command += std::to_wstring(STATUS_ACCESS_VIOLATION);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_command.c_str()));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_win32k_unittest.cc b/sandbox/win/src/process_mitigations_win32k_unittest.cc
new file mode 100644
index 0000000..4c7dba4
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_unittest.cc
@@ -0,0 +1,687 @@
+// 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 "sandbox/win/src/process_mitigations.h"
+
+#include <windows.h>
+
+#include <d3d9.h>
+#include <initguid.h>
+#include <opmapi.h>
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+BOOL CALLBACK MonitorEnumCallback(HMONITOR monitor,
+                                  HDC hdc_monitor,
+                                  LPRECT rect_monitor,
+                                  LPARAM data) {
+  std::map<HMONITOR, base::string16>& monitors =
+      *reinterpret_cast<std::map<HMONITOR, base::string16>*>(data);
+  MONITORINFOEXW monitor_info = {};
+  monitor_info.cbSize = sizeof(monitor_info);
+
+  if (!::GetMonitorInfoW(monitor,
+                         reinterpret_cast<MONITORINFO*>(&monitor_info)))
+    return FALSE;
+  monitors[monitor] = monitor_info.szDevice;
+  return TRUE;
+}
+
+std::map<HMONITOR, base::string16> EnumerateMonitors() {
+  std::map<HMONITOR, base::string16> result;
+  ::EnumDisplayMonitors(nullptr, nullptr, MonitorEnumCallback,
+                        reinterpret_cast<LPARAM>(&result));
+  return result;
+}
+
+#define HMONITOR_ENTRY(monitor)                 \
+  result[reinterpret_cast<HMONITOR>(monitor)] = \
+      base::StringPrintf(L"\\\\.\\DISPLAY%X", monitor)
+
+std::map<HMONITOR, base::string16> GetTestMonitors() {
+  std::map<HMONITOR, base::string16> result;
+
+  HMONITOR_ENTRY(0x11111111);
+  HMONITOR_ENTRY(0x22222222);
+  HMONITOR_ENTRY(0x44444444);
+  HMONITOR_ENTRY(0x88888888);
+  return result;
+}
+
+base::string16 UnicodeStringToString(PUNICODE_STRING name) {
+  return base::string16(
+      name->Buffer, name->Buffer + (name->Length / sizeof(name->Buffer[0])));
+}
+
+// Returns an index 1, 2, 4 or 8 depening on the device. 0 on error.
+DWORD GetTestDeviceMonitorIndex(PUNICODE_STRING device_name) {
+  base::string16 name = UnicodeStringToString(device_name);
+  std::map<HMONITOR, base::string16> monitors = GetTestMonitors();
+  for (const auto& monitor : monitors) {
+    if (name == monitor.second)
+      return static_cast<DWORD>(reinterpret_cast<uintptr_t>(monitor.first)) &
+             0xF;
+  }
+  return 0;
+}
+
+NTSTATUS WINAPI GetSuggestedOPMProtectedOutputArraySizeTest(
+    PUNICODE_STRING device_name,
+    DWORD* suggested_output_array_size) {
+  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
+  if (!monitor)
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+  *suggested_output_array_size = monitor;
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI
+CreateOPMProtectedOutputsTest(PUNICODE_STRING device_name,
+                              DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+                              DWORD output_array_size,
+                              DWORD* num_in_output_array,
+                              OPM_PROTECTED_OUTPUT_HANDLE* output_array) {
+  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
+  if (!monitor)
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+  if (vos != DXGKMDT_OPM_VOS_OPM_SEMANTICS)
+    return STATUS_INVALID_PARAMETER;
+  if (output_array_size != monitor)
+    return STATUS_INVALID_PARAMETER;
+  *num_in_output_array = monitor - 1;
+  for (DWORD index = 0; index < monitor - 1; ++index) {
+    output_array[index] =
+        reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE>((monitor << 4) + index);
+  }
+  return STATUS_SUCCESS;
+}
+
+ULONG CalculateCertLength(ULONG monitor) {
+  return (monitor * 0x800) + 0xabc;
+}
+
+NTSTATUS WINAPI GetCertificateTest(PUNICODE_STRING device_name,
+                                   DXGKMDT_CERTIFICATE_TYPE certificate_type,
+                                   BYTE* certificate,
+                                   ULONG certificate_length) {
+  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
+  if (!monitor)
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+    return STATUS_INVALID_PARAMETER;
+  if (certificate_length != CalculateCertLength(monitor))
+    return STATUS_INVALID_PARAMETER;
+  memset(certificate, 'A' + monitor, certificate_length);
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI
+GetCertificateSizeTest(PUNICODE_STRING device_name,
+                       DXGKMDT_CERTIFICATE_TYPE certificate_type,
+                       ULONG* certificate_length) {
+  DWORD monitor = GetTestDeviceMonitorIndex(device_name);
+  if (!monitor)
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+    return STATUS_INVALID_PARAMETER;
+  *certificate_length = CalculateCertLength(monitor);
+  return STATUS_SUCCESS;
+}
+
+// Check for valid output handle and return the monitor index.
+DWORD IsValidProtectedOutput(OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
+  uintptr_t handle = reinterpret_cast<uintptr_t>(protected_output);
+  uintptr_t monitor = handle >> 4;
+  uintptr_t index = handle & 0xF;
+  switch (monitor) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+      break;
+    default:
+      return 0;
+  }
+  if (index >= (monitor - 1))
+    return 0;
+  return static_cast<DWORD>(monitor);
+}
+
+NTSTATUS WINAPI
+GetCertificateByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+                           DXGKMDT_CERTIFICATE_TYPE certificate_type,
+                           BYTE* certificate,
+                           ULONG certificate_length) {
+  DWORD monitor = IsValidProtectedOutput(protected_output);
+  if (!monitor)
+    return STATUS_INVALID_HANDLE;
+  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+    return STATUS_INVALID_PARAMETER;
+  if (certificate_length != CalculateCertLength(monitor))
+    return STATUS_INVALID_PARAMETER;
+  memset(certificate, 'A' + monitor, certificate_length);
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI
+GetCertificateSizeByHandleTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+                               DXGKMDT_CERTIFICATE_TYPE certificate_type,
+                               ULONG* certificate_length) {
+  DWORD monitor = IsValidProtectedOutput(protected_output);
+  if (!monitor)
+    return STATUS_INVALID_HANDLE;
+  if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+    return STATUS_INVALID_PARAMETER;
+  *certificate_length = CalculateCertLength(monitor);
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI
+DestroyOPMProtectedOutputTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
+  if (!IsValidProtectedOutput(protected_output))
+    return STATUS_INVALID_HANDLE;
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI ConfigureOPMProtectedOutputTest(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+    ULONG additional_parameters_size,
+    const BYTE* additional_parameters) {
+  if (!IsValidProtectedOutput(protected_output))
+    return STATUS_INVALID_HANDLE;
+  if (additional_parameters && additional_parameters_size)
+    return STATUS_INVALID_PARAMETER;
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI GetOPMInformationTest(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+    DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information) {
+  DWORD monitor = IsValidProtectedOutput(protected_output);
+  if (!monitor)
+    return STATUS_INVALID_HANDLE;
+  memset(requested_information, '0' + monitor,
+         sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION));
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI
+GetOPMRandomNumberTest(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+                       DXGKMDT_OPM_RANDOM_NUMBER* random_number) {
+  DWORD monitor = IsValidProtectedOutput(protected_output);
+  if (!monitor)
+    return STATUS_INVALID_HANDLE;
+  memset(random_number->abRandomNumber, '!' + monitor,
+         sizeof(random_number->abRandomNumber));
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI SetOPMSigningKeyAndSequenceNumbersTest(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) {
+  DWORD monitor = IsValidProtectedOutput(protected_output);
+  if (!monitor)
+    return STATUS_INVALID_HANDLE;
+  DXGKMDT_OPM_ENCRYPTED_PARAMETERS test_params = {};
+  memset(test_params.abEncryptedParameters, 'a' + monitor,
+         sizeof(test_params.abEncryptedParameters));
+  if (memcmp(test_params.abEncryptedParameters,
+             parameters->abEncryptedParameters,
+             sizeof(test_params.abEncryptedParameters)) != 0)
+    return STATUS_INVALID_PARAMETER;
+  return STATUS_SUCCESS;
+}
+
+BOOL WINAPI EnumDisplayMonitorsTest(HDC hdc,
+                                    LPCRECT clip_rect,
+                                    MONITORENUMPROC enum_function,
+                                    LPARAM data) {
+  RECT rc = {};
+  for (const auto& monitor : GetTestMonitors()) {
+    if (!enum_function(monitor.first, hdc, &rc, data))
+      return FALSE;
+  }
+  return TRUE;
+}
+
+BOOL WINAPI GetMonitorInfoWTest(HMONITOR monitor, LPMONITORINFO monitor_info) {
+  std::map<HMONITOR, base::string16> monitors = GetTestMonitors();
+  if (monitor_info->cbSize != sizeof(MONITORINFO) &&
+      monitor_info->cbSize != sizeof(MONITORINFOEXW))
+    return FALSE;
+  auto it = monitors.find(monitor);
+  if (it == monitors.end())
+    return FALSE;
+  if (monitor_info->cbSize == sizeof(MONITORINFOEXW)) {
+    MONITORINFOEXW* monitor_info_ex =
+        reinterpret_cast<MONITORINFOEXW*>(monitor_info);
+    size_t copy_size = (it->second.size() + 1) * sizeof(WCHAR);
+    if (copy_size > sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR))
+      copy_size = sizeof(monitor_info_ex->szDevice) - sizeof(WCHAR);
+    memset(monitor_info_ex->szDevice, 0, sizeof(monitor_info_ex->szDevice));
+    memcpy(monitor_info_ex->szDevice, it->second.c_str(), copy_size);
+  }
+  return TRUE;
+}
+
+#define RETURN_TEST_FUNC(n)    \
+  if (strcmp(name, #n) == 0) { \
+    return n##Test;            \
+  }
+
+void* FunctionOverrideForTest(const char* name) {
+  RETURN_TEST_FUNC(GetSuggestedOPMProtectedOutputArraySize);
+  RETURN_TEST_FUNC(CreateOPMProtectedOutputs);
+  RETURN_TEST_FUNC(GetCertificate);
+  RETURN_TEST_FUNC(GetCertificateSize);
+  RETURN_TEST_FUNC(DestroyOPMProtectedOutput);
+  RETURN_TEST_FUNC(ConfigureOPMProtectedOutput);
+  RETURN_TEST_FUNC(GetOPMInformation);
+  RETURN_TEST_FUNC(GetOPMRandomNumber);
+  RETURN_TEST_FUNC(SetOPMSigningKeyAndSequenceNumbers);
+  RETURN_TEST_FUNC(EnumDisplayMonitors);
+  RETURN_TEST_FUNC(GetMonitorInfoW);
+  RETURN_TEST_FUNC(GetCertificateByHandle);
+  RETURN_TEST_FUNC(GetCertificateSizeByHandle);
+  NOTREACHED();
+  return nullptr;
+}
+
+bool RunTestsOnVideoOutputConfigure(uintptr_t monitor_index,
+                                    IOPMVideoOutput* video_output) {
+  OPM_CONFIGURE_PARAMETERS config_params = {};
+  OPM_SET_PROTECTION_LEVEL_PARAMETERS* protection_level =
+      reinterpret_cast<OPM_SET_PROTECTION_LEVEL_PARAMETERS*>(
+          config_params.abParameters);
+  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP;
+  protection_level->ulProtectionLevel = OPM_HDCP_ON;
+  config_params.guidSetting = OPM_SET_PROTECTION_LEVEL;
+  config_params.cbParametersSize = sizeof(OPM_SET_PROTECTION_LEVEL_PARAMETERS);
+  HRESULT hr = video_output->Configure(&config_params, 0, nullptr);
+  if (FAILED(hr))
+    return false;
+  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_DPCP;
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (FAILED(hr))
+    return false;
+  protection_level->ulProtectionLevel = OPM_HDCP_OFF;
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (FAILED(hr))
+    return false;
+  BYTE dummy_byte = 0;
+  hr = video_output->Configure(&config_params, 1, &dummy_byte);
+  if (SUCCEEDED(hr))
+    return false;
+  protection_level->ulProtectionType = 0xFFFFFFFF;
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (SUCCEEDED(hr))
+    return false;
+  // Invalid protection level test.
+  protection_level->ulProtectionType = OPM_PROTECTION_TYPE_HDCP;
+  protection_level->ulProtectionLevel = OPM_HDCP_ON + 1;
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (SUCCEEDED(hr))
+    return false;
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (SUCCEEDED(hr))
+    return false;
+  config_params.guidSetting = OPM_SET_HDCP_SRM;
+  OPM_SET_HDCP_SRM_PARAMETERS* srm_parameters =
+      reinterpret_cast<OPM_SET_HDCP_SRM_PARAMETERS*>(
+          config_params.abParameters);
+  srm_parameters->ulSRMVersion = 1;
+  config_params.cbParametersSize = sizeof(OPM_SET_HDCP_SRM_PARAMETERS);
+  hr = video_output->Configure(&config_params, 0, nullptr);
+  if (SUCCEEDED(hr))
+    return false;
+  return true;
+}
+
+bool RunTestsOnVideoOutputFinishInitialization(uintptr_t monitor_index,
+                                               IOPMVideoOutput* video_output) {
+  OPM_ENCRYPTED_INITIALIZATION_PARAMETERS init_params = {};
+  memset(init_params.abEncryptedInitializationParameters, 'a' + monitor_index,
+         sizeof(init_params.abEncryptedInitializationParameters));
+  HRESULT hr = video_output->FinishInitialization(&init_params);
+  if (FAILED(hr))
+    return false;
+  memset(init_params.abEncryptedInitializationParameters, 'Z' + monitor_index,
+         sizeof(init_params.abEncryptedInitializationParameters));
+  hr = video_output->FinishInitialization(&init_params);
+  if (SUCCEEDED(hr))
+    return false;
+  return true;
+}
+
+bool RunTestsOnVideoOutputStartInitialization(uintptr_t monitor_index,
+                                              IOPMVideoOutput* video_output) {
+  OPM_RANDOM_NUMBER random_number = {};
+  BYTE* certificate = nullptr;
+  ULONG certificate_length = 0;
+
+  HRESULT hr = video_output->StartInitialization(&random_number, &certificate,
+                                                 &certificate_length);
+  if (FAILED(hr))
+    return false;
+
+  if (certificate_length != CalculateCertLength(monitor_index))
+    return false;
+
+  for (ULONG i = 0; i < certificate_length; ++i) {
+    if (certificate[i] != 'A' + monitor_index)
+      return false;
+  }
+
+  for (ULONG i = 0; i < sizeof(random_number.abRandomNumber); ++i) {
+    if (random_number.abRandomNumber[i] != '!' + monitor_index)
+      return false;
+  }
+
+  return true;
+}
+
+static bool SendSingleGetInfoRequest(uintptr_t monitor_index,
+                                     IOPMVideoOutput* video_output,
+                                     const GUID& request,
+                                     ULONG data_length,
+                                     void* data) {
+  OPM_GET_INFO_PARAMETERS params = {};
+  OPM_REQUESTED_INFORMATION requested_information = {};
+  BYTE* requested_information_ptr =
+      reinterpret_cast<BYTE*>(&requested_information);
+  params.guidInformation = request;
+  params.cbParametersSize = data_length;
+  memcpy(params.abParameters, data, data_length);
+  HRESULT hr = video_output->GetInformation(&params, &requested_information);
+  if (FAILED(hr))
+    return false;
+  for (size_t i = 0; i < sizeof(OPM_REQUESTED_INFORMATION); ++i) {
+    if (requested_information_ptr[i] != '0' + monitor_index)
+      return false;
+  }
+  return true;
+}
+
+bool RunTestsOnVideoOutputGetInformation(uintptr_t monitor_index,
+                                         IOPMVideoOutput* video_output) {
+  ULONG dummy = 0;
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_CONNECTOR_TYPE, 0, nullptr)) {
+    return false;
+  }
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_SUPPORTED_PROTECTION_TYPES, 0,
+                                nullptr)) {
+    return false;
+  }
+  // These should fail due to invalid parameter sizes.
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_CONNECTOR_TYPE, sizeof(dummy), &dummy)) {
+    return false;
+  }
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_SUPPORTED_PROTECTION_TYPES,
+                               sizeof(dummy), &dummy)) {
+    return false;
+  }
+  ULONG protection_type = OPM_PROTECTION_TYPE_HDCP;
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_ACTUAL_PROTECTION_LEVEL,
+                                sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  protection_type = OPM_PROTECTION_TYPE_DPCP;
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_ACTUAL_PROTECTION_LEVEL,
+                                sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  // These should fail as unsupported or invalid parameters.
+  protection_type = OPM_PROTECTION_TYPE_ACP;
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_ACTUAL_PROTECTION_LEVEL,
+                               sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_ACTUAL_PROTECTION_LEVEL, 0, nullptr)) {
+    return false;
+  }
+  protection_type = OPM_PROTECTION_TYPE_HDCP;
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_VIRTUAL_PROTECTION_LEVEL,
+                                sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  protection_type = OPM_PROTECTION_TYPE_DPCP;
+  if (!SendSingleGetInfoRequest(monitor_index, video_output,
+                                OPM_GET_VIRTUAL_PROTECTION_LEVEL,
+                                sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  // These should fail as unsupported or invalid parameters.
+  protection_type = OPM_PROTECTION_TYPE_ACP;
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_VIRTUAL_PROTECTION_LEVEL,
+                               sizeof(protection_type), &protection_type)) {
+    return false;
+  }
+  if (SendSingleGetInfoRequest(monitor_index, video_output,
+                               OPM_GET_VIRTUAL_PROTECTION_LEVEL, 0, nullptr)) {
+    return false;
+  }
+  // This should fail with unsupported request.
+  if (SendSingleGetInfoRequest(monitor_index, video_output, OPM_GET_CODEC_INFO,
+                               0, nullptr)) {
+    return false;
+  }
+  return true;
+}
+
+int RunTestsOnVideoOutput(uintptr_t monitor_index,
+                          IOPMVideoOutput* video_output) {
+  if (!RunTestsOnVideoOutputStartInitialization(monitor_index, video_output))
+    return sandbox::SBOX_TEST_FIRST_ERROR;
+
+  if (!RunTestsOnVideoOutputFinishInitialization(monitor_index, video_output))
+    return sandbox::SBOX_TEST_SECOND_ERROR;
+
+  if (!RunTestsOnVideoOutputConfigure(monitor_index, video_output))
+    return sandbox::SBOX_TEST_THIRD_ERROR;
+
+  if (!RunTestsOnVideoOutputGetInformation(monitor_index, video_output))
+    return sandbox::SBOX_TEST_FOURTH_ERROR;
+
+  return sandbox::SBOX_TEST_SUCCEEDED;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+//------------------------------------------------------------------------------
+// Exported functions called by child test processes.
+//------------------------------------------------------------------------------
+
+SBOX_TESTS_COMMAND int CheckWin8MonitorsRedirection(int argc, wchar_t** argv) {
+  std::map<HMONITOR, base::string16> monitors = EnumerateMonitors();
+  std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors();
+  if (monitors.size() != monitors_to_test.size())
+    return SBOX_TEST_FIRST_ERROR;
+
+  for (const auto& monitor : monitors) {
+    auto result = monitors_to_test.find(monitor.first);
+    if (result == monitors_to_test.end())
+      return SBOX_TEST_SECOND_ERROR;
+    if (result->second != monitor.second)
+      return SBOX_TEST_THIRD_ERROR;
+  }
+  return SBOX_TEST_SUCCEEDED;
+}
+
+SBOX_TESTS_COMMAND int CheckWin8MonitorInfo(int argc, wchar_t** argv) {
+  std::map<HMONITOR, base::string16> monitors_to_test = GetTestMonitors();
+  MONITORINFO monitor_info = {};
+  MONITORINFOEXW monitor_info_exw = {};
+  MONITORINFOEXA monitor_info_exa = {};
+  HMONITOR valid_monitor = monitors_to_test.begin()->first;
+  base::string16 valid_device = monitors_to_test.begin()->second;
+  monitor_info.cbSize = sizeof(MONITORINFO);
+  if (!::GetMonitorInfoW(valid_monitor, &monitor_info))
+    return SBOX_TEST_FIRST_ERROR;
+  monitor_info.cbSize = sizeof(MONITORINFO);
+  if (!::GetMonitorInfoA(valid_monitor, &monitor_info))
+    return SBOX_TEST_SECOND_ERROR;
+  monitor_info_exw.cbSize = sizeof(MONITORINFOEXW);
+  if (!::GetMonitorInfoW(valid_monitor,
+                         reinterpret_cast<MONITORINFO*>(&monitor_info_exw)) ||
+      valid_device != monitor_info_exw.szDevice) {
+    return SBOX_TEST_THIRD_ERROR;
+  }
+  monitor_info_exa.cbSize = sizeof(MONITORINFOEXA);
+  if (!::GetMonitorInfoA(valid_monitor,
+                         reinterpret_cast<MONITORINFO*>(&monitor_info_exa)) ||
+      valid_device != base::ASCIIToUTF16(monitor_info_exa.szDevice)) {
+    return SBOX_TEST_FOURTH_ERROR;
+  }
+
+  // Invalid size checks.
+  monitor_info.cbSize = 0;
+  if (::GetMonitorInfoW(valid_monitor, &monitor_info))
+    return SBOX_TEST_FIFTH_ERROR;
+  monitor_info.cbSize = 0x10000;
+  if (::GetMonitorInfoW(valid_monitor, &monitor_info))
+    return SBOX_TEST_SIXTH_ERROR;
+
+  // Check that an invalid handle isn't accepted.
+  HMONITOR invalid_monitor = reinterpret_cast<HMONITOR>(-1);
+  monitor_info.cbSize = sizeof(MONITORINFO);
+  if (::GetMonitorInfoW(invalid_monitor, &monitor_info))
+    return SBOX_TEST_SEVENTH_ERROR;
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+SBOX_TESTS_COMMAND int CheckWin8OPMApis(int argc, wchar_t** argv) {
+  std::map<HMONITOR, base::string16> monitors = GetTestMonitors();
+  for (const auto& monitor : monitors) {
+    ULONG output_count = 0;
+    IOPMVideoOutput** outputs = nullptr;
+    uintptr_t monitor_index = reinterpret_cast<uintptr_t>(monitor.first) & 0xF;
+    HRESULT hr = OPMGetVideoOutputsFromHMONITOR(
+        monitor.first, OPM_VOS_OPM_SEMANTICS, &output_count, &outputs);
+    if (monitor_index > 4) {
+      // These should fail because the certificate is too large.
+      if (SUCCEEDED(hr))
+        return SBOX_TEST_FIRST_ERROR;
+      continue;
+    }
+    if (FAILED(hr))
+      return SBOX_TEST_SECOND_ERROR;
+    if (output_count != monitor_index - 1)
+      return SBOX_TEST_THIRD_ERROR;
+    for (ULONG output_index = 0; output_index < output_count; ++output_index) {
+      int result = RunTestsOnVideoOutput(monitor_index, outputs[output_index]);
+      outputs[output_index]->Release();
+      if (result != SBOX_TEST_SUCCEEDED)
+        return result;
+    }
+    ::CoTaskMemFree(outputs);
+  }
+  return SBOX_TEST_SUCCEEDED;
+}
+
+//------------------------------------------------------------------------------
+// Exported Win32k Lockdown Tests
+//------------------------------------------------------------------------------
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on
+// the target process causes the launch to fail in process initialization.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsWin32kTest, CheckWin8LockDownFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_policy_command = L"CheckPolicy ";
+  test_policy_command += std::to_wstring(TESTPOLICY_WIN32K);
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(test_policy_command.c_str()));
+}
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation
+// along with the policy to fake user32 and gdi32 initialization successfully
+// launches the target process.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsWin32kTest, CheckWin8LockDownSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_policy_command = L"CheckPolicy ";
+  test_policy_command += std::to_wstring(TESTPOLICY_WIN32K);
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+  ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
+      FunctionOverrideForTest);
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                            sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL),
+            sandbox::SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_policy_command.c_str()));
+  EXPECT_NE(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"CheckWin8MonitorsRedirection"));
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo"));
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis"));
+}
+
+// This test validates the even though we're running under win32k lockdown
+// we can use the IPC redirection to enumerate the list of monitors.
+TEST(ProcessMitigationsWin32kTest, CheckWin8Redirection) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  base::string16 test_policy_command = L"CheckPolicy ";
+  test_policy_command += std::to_wstring(TESTPOLICY_WIN32K);
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+  ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
+      FunctionOverrideForTest);
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                            sandbox::TargetPolicy::IMPLEMENT_OPM_APIS, NULL),
+            sandbox::SBOX_ALL_OK);
+  policy->SetEnableOPMRedirection();
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(test_policy_command.c_str()));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"CheckWin8MonitorsRedirection"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8MonitorInfo"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8OPMApis"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/tests/integration_tests/hooking_dll.cc b/sandbox/win/tests/integration_tests/hooking_dll.cc
index f275ae6..4dffe047 100644
--- a/sandbox/win/tests/integration_tests/hooking_dll.cc
+++ b/sandbox/win/tests/integration_tests/hooking_dll.cc
@@ -5,8 +5,8 @@
 #include <stdio.h>
 #include <windows.h>
 
-#define _DLL_EXPORTING
-#include "integration_tests_common.h"
+#define BUILDING_DLL
+#include "hooking_dll.h"
 
 // This data section creates a common area that is accessible
 // to all instances of the DLL (in every process).  They map to
@@ -24,10 +24,11 @@
 #pragma comment(linker, "/SECTION:.hook,RWS")
 
 namespace {
-
 HANDLE event = NULL;
 }
 
+namespace hooking_dll {
+
 void SetHook(HHOOK hook_handle) {
   hook = hook_handle;
 
@@ -50,14 +51,16 @@
   return CallNextHookEx(hook, code, w_param, l_param);
 }
 
+}  // namespace hooking_dll
+
 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
   if (reason == DLL_PROCESS_ATTACH) {
     // The testing process should have set up this named event already
     // (if the test needs this event to be signaled).
-    event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE, g_hook_event);
+    event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE, hooking_dll::g_hook_event);
   }
 
-  if (reason == DLL_PROCESS_DETACH)
+  if (reason == DLL_PROCESS_DETACH && event != nullptr)
     ::CloseHandle(event);
 
   return TRUE;
diff --git a/sandbox/win/tests/integration_tests/hooking_dll.h b/sandbox/win/tests/integration_tests/hooking_dll.h
new file mode 100644
index 0000000..a52b7b4
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/hooking_dll.h
@@ -0,0 +1,27 @@
+// 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 SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_DLL_H_
+#define SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_DLL_H_
+
+#include <windows.h>
+
+#ifdef BUILDING_DLL
+#define DLL_EXPORT __declspec(dllexport)
+#else
+#define DLL_EXPORT __declspec(dllimport)
+#endif
+
+namespace hooking_dll {
+
+constexpr wchar_t g_hook_dll_file[] = L"sbox_integration_test_hook_dll.dll";
+constexpr wchar_t g_hook_event[] = L"ChromeExtensionTestHookEvent";
+
+DLL_EXPORT void SetHook(HHOOK hook_handle);
+DLL_EXPORT bool WasHookCalled();
+DLL_EXPORT LRESULT HookProc(int code, WPARAM w_param, LPARAM l_param);
+
+}  // namespace hooking_dll
+
+#endif  // SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_DLL_H_
diff --git a/sandbox/win/tests/integration_tests/hooking_win_proc.cc b/sandbox/win/tests/integration_tests/hooking_win_proc.cc
index 3c6770abff..0c00edb 100644
--- a/sandbox/win/tests/integration_tests/hooking_win_proc.cc
+++ b/sandbox/win/tests/integration_tests/hooking_win_proc.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "integration_tests_common.h"
-
 #include <windows.h>
 
+#include "hooking_win_proc.h"
+
 LRESULT CALLBACK WndProc(HWND window,
                          UINT message,
                          WPARAM w_param,
@@ -33,8 +33,12 @@
                    HINSTANCE prev_instance,
                    LPSTR cmd_line,
                    int cmd_show) {
+  constexpr wchar_t winproc_class_name[] = L"myWindowClass";
+  constexpr wchar_t winproc_window_name[] = L"ChromeMitigationTests";
+
   // The parent process should have set up this named event already.
-  HANDLE event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE, g_winproc_event);
+  HANDLE event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE,
+                              hooking_win_proc::g_winproc_event);
   if (event == NULL || event == INVALID_HANDLE_VALUE)
     return 1;
 
@@ -50,17 +54,17 @@
   window_class.hCursor = ::LoadCursor(NULL, IDC_ARROW);
   window_class.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOWFRAME);
   window_class.lpszMenuName = NULL;
-  window_class.lpszClassName = g_winproc_class_name;
+  window_class.lpszClassName = winproc_class_name;
   window_class.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);
 
   if (!::RegisterClassEx(&window_class))
     return 1;
 
   // Step 2: Create the Window.
-  HWND window = ::CreateWindowExW(WS_EX_CLIENTEDGE, g_winproc_class_name,
-                                  g_winproc_window_name, WS_OVERLAPPEDWINDOW,
-                                  CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL,
-                                  NULL, instance, NULL);
+  HWND window =
+      ::CreateWindowExW(WS_EX_CLIENTEDGE, winproc_class_name,
+                        winproc_window_name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
+                        CW_USEDEFAULT, 240, 120, NULL, NULL, instance, NULL);
 
   if (window == NULL)
     return 1;
diff --git a/sandbox/win/tests/integration_tests/hooking_win_proc.h b/sandbox/win/tests/integration_tests/hooking_win_proc.h
new file mode 100644
index 0000000..eb5e5e1e
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/hooking_win_proc.h
@@ -0,0 +1,17 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_WIN_PROC_H_
+#define SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_WIN_PROC_H_
+
+#include <windows.h>
+
+namespace hooking_win_proc {
+
+constexpr wchar_t g_winproc_file[] = L"sbox_integration_test_win_proc.exe ";
+constexpr wchar_t g_winproc_event[] = L"ChromeExtensionTestEvent";
+
+}  // namespace hooking_win_proc
+
+#endif  // SANDBOX_TESTS_INTEGRATION_TESTS_HOOKING_WIN_PROC_H_
diff --git a/sandbox/win/tests/integration_tests/integration_tests.cc b/sandbox/win/tests/integration_tests/integration_tests.cc
index 3920da1..5c32c60 100644
--- a/sandbox/win/tests/integration_tests/integration_tests.cc
+++ b/sandbox/win/tests/integration_tests/integration_tests.cc
@@ -5,8 +5,20 @@
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "base/test/test_timeouts.h"
 #include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+// Common function used for timeout with Win APIs like ::WaitForSingleObject().
+DWORD SboxTestEventTimeout() {
+  if (::IsDebuggerPresent())
+    return INFINITE;
+
+  return static_cast<DWORD>(
+      (TestTimeouts::action_timeout()).InMillisecondsRoundedUp());
+}
+}
 
 int wmain(int argc, wchar_t **argv) {
   if (argc >= 2) {
diff --git a/sandbox/win/tests/integration_tests/integration_tests_common.h b/sandbox/win/tests/integration_tests/integration_tests_common.h
index 841e6e4b..0c6eff1 100644
--- a/sandbox/win/tests/integration_tests/integration_tests_common.h
+++ b/sandbox/win/tests/integration_tests/integration_tests_common.h
@@ -7,37 +7,25 @@
 
 #include <windows.h>
 
-// Use the same header file for DLL and importers.
-#ifdef _DLL_EXPORTING
-#define DECLSPEC extern "C" __declspec(dllexport)
-#else
-#define DECLSPEC extern "C" __declspec(dllimport)
-#endif
+namespace sandbox {
 
 //------------------------------------------------------------------------------
-// Tests
+// Common - for sharing between source files.
 //------------------------------------------------------------------------------
-const wchar_t* g_extension_point_test_mutex = L"ChromeExtensionTestMutex";
+enum TestPolicy {
+  TESTPOLICY_DEP = 1,
+  TESTPOLICY_ASLR,
+  TESTPOLICY_STRICTHANDLE,
+  TESTPOLICY_WIN32K,
+  TESTPOLICY_EXTENSIONPOINT,
+  TESTPOLICY_NONSYSFONT,
+  TESTPOLICY_LOADNOREMOTE,
+  TESTPOLICY_LOADNOLOW,
+};
 
-//------------------------------------------------------------------------------
-// Hooking WinProc exe.
-//------------------------------------------------------------------------------
-const wchar_t* g_winproc_file = L"sbox_integration_test_win_proc.exe ";
-const wchar_t* g_winproc_class_name = L"myWindowClass";
-const wchar_t* g_winproc_window_name = L"ChromeMitigationTests";
-const wchar_t* g_winproc_event = L"ChromeExtensionTestEvent";
+// Timeout for ::WaitForSingleObject synchronization.
+DWORD SboxTestEventTimeout();
 
-//------------------------------------------------------------------------------
-// Hooking dll.
-//------------------------------------------------------------------------------
-const wchar_t* g_hook_dll_file = L"sbox_integration_test_hook_dll.dll";
-const wchar_t* g_hook_event = L"ChromeExtensionTestHookEvent";
-const char* g_hook_handler_func = "HookProc";
-const char* g_was_hook_called_func = "WasHookCalled";
-const char* g_set_hook_func = "SetHook";
-
-DECLSPEC LRESULT HookProc(int code, WPARAM wParam, LPARAM lParam);
-DECLSPEC bool WasHookCalled();
-DECLSPEC void SetHook(HHOOK hook_handle);
+}  // namespace sandbox
 
 #endif  // SANDBOX_TESTS_INTEGRATION_TESTS_COMMON_H_
diff --git a/services/OWNERS b/services/OWNERS
index f5ec3de..82541da 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,3 +1,6 @@
 ben@chromium.org
+blundell@chromium.org
 jam@chromium.org
 rockot@chromium.org
+sky@chromium.org
+yzshen@chromium.org
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index 577dfe0..8a3de467 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -63,6 +63,7 @@
     "battery/battery_status_service_unittest.cc",
     "generic_sensor/generic_sensor_service_unittest.cc",
     "generic_sensor/platform_sensor_and_provider_unittest_win.cc",
+    "generic_sensor/platform_sensor_provider_unittest_android.cc",
     "power_monitor/power_monitor_message_broadcaster_unittest.cc",
     "public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc",
     "vibration/vibration_manager_impl_unittest.cc",
diff --git a/services/device/generic_sensor/README.md b/services/device/generic_sensor/README.md
index 8e10d13..0e59c0a 100644
--- a/services/device/generic_sensor/README.md
+++ b/services/device/generic_sensor/README.md
@@ -14,17 +14,17 @@
 table. An empty cell indicates that the sensor type is not supported on that
 platform.
 
-| SensorType           | Android                   | Linux          | macOS              | Windows                                   |
-| -------------------- | ------------------------- | -------------- | ------------------ | ----------------------------------------- |
-| AMBIENT_LIGHT        | TYPE_LIGHT                | in_illuminance | AppleLMUController | SENSOR_TYPE_AMBIENT_LIGHT                 |
-| PROXIMITY            |                           |                |                    |                                           |
-| ACCELEROMETER        | TYPE_ACCELEROMETER        | in_accel       | SMCMotionSensor    | SENSOR_TYPE_ACCELEROMETER_3D              |
-| LINEAR_ACCELEROMETER | TYPE_LINEAR_ACCELEROMETER |                |                    |                                           |
-| GYROSCOPE            | TYPE_GYROSCOPE            | in_anglvel     |                    | SENSOR_TYPE_GYROMETER_3D                  |
-| MAGNETOMETER         | TYPE_MAGNETIC_FIELD       | in_magn        |                    | SENSOR_TYPE_COMPASS_3D                    |
-| PRESSURE             |                           |                |                    |                                           |
-| ABSOLUTE_ORIENTATION | TYPE_ROTATION_VECTOR      |                |                    | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
-| RELATIVE_ORIENTATION | TYPE_GAME_ROTATION_VECTOR |                |                    |                                           |
+| SensorType                      | Android                   | Linux          | macOS              | Windows                                   |
+| ------------------------------- | ------------------------- | -------------- | ------------------ | ----------------------------------------- |
+| AMBIENT_LIGHT                   | TYPE_LIGHT                | in_illuminance | AppleLMUController | SENSOR_TYPE_AMBIENT_LIGHT                 |
+| PROXIMITY                       |                           |                |                    |                                           |
+| ACCELEROMETER                   | TYPE_ACCELEROMETER        | in_accel       | SMCMotionSensor    | SENSOR_TYPE_ACCELEROMETER_3D              |
+| LINEAR_ACCELEROMETER            | TYPE_LINEAR_ACCELEROMETER |                |                    |                                           |
+| GYROSCOPE                       | TYPE_GYROSCOPE            | in_anglvel     |                    | SENSOR_TYPE_GYROMETER_3D                  |
+| MAGNETOMETER                    | TYPE_MAGNETIC_FIELD       | in_magn        |                    | SENSOR_TYPE_COMPASS_3D                    |
+| PRESSURE                        |                           |                |                    |                                           |
+| ABSOLUTE_ORIENTATION_QUATERNION | TYPE_ROTATION_VECTOR      |                |                    | SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION |
+| RELATIVE_ORIENTATION_QUATERNION | TYPE_GAME_ROTATION_VECTOR |                |                    |                                           |
 
 ### Android
 
diff --git a/services/device/generic_sensor/android/java/src/org/chromium/device/sensors/PlatformSensorProvider.java b/services/device/generic_sensor/android/java/src/org/chromium/device/sensors/PlatformSensorProvider.java
index 18aebf0..b0043ec 100644
--- a/services/device/generic_sensor/android/java/src/org/chromium/device/sensors/PlatformSensorProvider.java
+++ b/services/device/generic_sensor/android/java/src/org/chromium/device/sensors/PlatformSensorProvider.java
@@ -29,7 +29,7 @@
      * creation and @see android.hardware.SensorEventListener registration.
      * @see android.hardware.SensorManager
      */
-    private final SensorManager mSensorManager;
+    private SensorManager mSensorManager;
 
     /**
      * Thread that is handling all sensor events.
@@ -136,6 +136,14 @@
     }
 
     /**
+     * Sets |mSensorManager| to null for testing purposes.
+     */
+    @CalledByNative
+    protected void setSensorManagerToNullForTesting() {
+        mSensorManager = null;
+    }
+
+    /**
      * Creates PlatformSensor instance.
      *
      * @param type type of a sensor.
@@ -156,9 +164,9 @@
                 return PlatformSensor.create(Sensor.TYPE_GYROSCOPE, 3, this);
             case SensorType.MAGNETOMETER:
                 return PlatformSensor.create(Sensor.TYPE_MAGNETIC_FIELD, 3, this);
-            case SensorType.ABSOLUTE_ORIENTATION:
+            case SensorType.ABSOLUTE_ORIENTATION_QUATERNION:
                 return PlatformSensor.create(Sensor.TYPE_ROTATION_VECTOR, 4, this);
-            case SensorType.RELATIVE_ORIENTATION:
+            case SensorType.RELATIVE_ORIENTATION_QUATERNION:
                 return PlatformSensor.create(Sensor.TYPE_GAME_ROTATION_VECTOR, 4, this);
             default:
                 return null;
diff --git a/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java b/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
index 82dab43..a759dd09 100644
--- a/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
+++ b/services/device/generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java
@@ -159,9 +159,9 @@
         verify(mSensorManager).getSensorList(Sensor.TYPE_GYROSCOPE);
         provider.createSensor(SensorType.MAGNETOMETER);
         verify(mSensorManager).getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
-        provider.createSensor(SensorType.ABSOLUTE_ORIENTATION);
+        provider.createSensor(SensorType.ABSOLUTE_ORIENTATION_QUATERNION);
         verify(mSensorManager).getSensorList(Sensor.TYPE_ROTATION_VECTOR);
-        provider.createSensor(SensorType.RELATIVE_ORIENTATION);
+        provider.createSensor(SensorType.RELATIVE_ORIENTATION_QUATERNION);
         verify(mSensorManager).getSensorList(Sensor.TYPE_GAME_ROTATION_VECTOR);
     }
 
diff --git a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
index 8bf01e83..c78040b4 100644
--- a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
+++ b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
@@ -678,12 +678,13 @@
        CheckDeviceOrientationReadingConversion) {
   mojo::ScopedSharedBufferHandle handle =
       PlatformSensorProviderWin::GetInstance()->CloneSharedBufferHandle();
-  mojo::ScopedSharedBufferMapping mapping = handle->MapAtOffset(
-      sizeof(SensorReadingSharedBuffer),
-      SensorReadingSharedBuffer::GetOffset(SensorType::ABSOLUTE_ORIENTATION));
+  mojo::ScopedSharedBufferMapping mapping =
+      handle->MapAtOffset(sizeof(SensorReadingSharedBuffer),
+                          SensorReadingSharedBuffer::GetOffset(
+                              SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
 
   SetSupportedSensor(SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION);
-  auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION);
+  auto sensor = CreateSensor(SensorType::ABSOLUTE_ORIENTATION_QUATERNION);
   EXPECT_TRUE(sensor);
 
   auto client = base::MakeUnique<NiceMock<MockPlatformSensorClient>>(sensor);
diff --git a/services/device/generic_sensor/platform_sensor_provider_android.cc b/services/device/generic_sensor/platform_sensor_provider_android.cc
index 0c60a1b..2532211 100644
--- a/services/device/generic_sensor/platform_sensor_provider_android.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_android.cc
@@ -28,6 +28,12 @@
 
 PlatformSensorProviderAndroid::~PlatformSensorProviderAndroid() = default;
 
+void PlatformSensorProviderAndroid::SetSensorManagerToNullForTesting() {
+  JNIEnv* env = AttachCurrentThread();
+  Java_PlatformSensorProvider_setSensorManagerToNullForTesting(env,
+                                                               j_object_.obj());
+}
+
 void PlatformSensorProviderAndroid::CreateSensorInternal(
     mojom::SensorType type,
     mojo::ScopedSharedBufferMapping mapping,
@@ -36,8 +42,10 @@
   ScopedJavaLocalRef<jobject> sensor = Java_PlatformSensorProvider_createSensor(
       env, j_object_.obj(), static_cast<jint>(type));
 
-  if (!sensor.obj())
+  if (!sensor.obj()) {
     callback.Run(nullptr);
+    return;
+  }
 
   scoped_refptr<PlatformSensorAndroid> concrete_sensor =
       new PlatformSensorAndroid(type, std::move(mapping), this, sensor);
diff --git a/services/device/generic_sensor/platform_sensor_provider_android.h b/services/device/generic_sensor/platform_sensor_provider_android.h
index 5a1610b..292b788c 100644
--- a/services/device/generic_sensor/platform_sensor_provider_android.h
+++ b/services/device/generic_sensor/platform_sensor_provider_android.h
@@ -18,6 +18,8 @@
 
   static PlatformSensorProviderAndroid* GetInstance();
 
+  void SetSensorManagerToNullForTesting();
+
  protected:
   void CreateSensorInternal(mojom::SensorType type,
                             mojo::ScopedSharedBufferMapping mapping,
diff --git a/services/device/generic_sensor/platform_sensor_provider_unittest_android.cc b/services/device/generic_sensor/platform_sensor_provider_unittest_android.cc
new file mode 100644
index 0000000..5fa918c8
--- /dev/null
+++ b/services/device/generic_sensor/platform_sensor_provider_unittest_android.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/device/generic_sensor/platform_sensor_provider_android.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+class PlatformSensorProviderTestAndroid : public testing::Test {
+ public:
+  PlatformSensorProviderTestAndroid() = default;
+
+  void SetUp() override {
+    provider_ = PlatformSensorProviderAndroid::GetInstance();
+    ASSERT_TRUE(provider_);
+  }
+
+  void CreateSensorCallback(scoped_refptr<PlatformSensor> sensor) {
+    EXPECT_FALSE(sensor);
+  }
+
+ protected:
+  PlatformSensorProviderAndroid* provider_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PlatformSensorProviderTestAndroid);
+};
+
+TEST_F(PlatformSensorProviderTestAndroid, SensorManagerIsNull) {
+  provider_->SetSensorManagerToNullForTesting();
+  provider_->CreateSensor(
+      device::mojom::SensorType::AMBIENT_LIGHT,
+      base::Bind(&PlatformSensorProviderTestAndroid::CreateSensorCallback,
+                 base::Unretained(this)));
+}
+
+}  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.cc b/services/device/generic_sensor/platform_sensor_provider_win.cc
index 07ffe2eb..cabed87 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -54,7 +54,7 @@
 
   HRESULT hr = ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
                                   IID_PPV_ARGS(&sensor_manager_));
-  return SUCCEEDED(hr);
+  return SUCCEEDED(hr) && sensor_manager_.Get();
 }
 
 void PlatformSensorProviderWin::AllSensorsRemoved() {
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.cc b/services/device/generic_sensor/platform_sensor_reader_win.cc
index b8a16d3..d98fcf1 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -211,7 +211,7 @@
       return CreateGyroscopeReaderInitParams();
     case mojom::SensorType::MAGNETOMETER:
       return CreateMagnetometerReaderInitParams();
-    case mojom::SensorType::ABSOLUTE_ORIENTATION:
+    case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
       return CreateAbsoluteOrientationReaderInitParams();
     default:
       NOTIMPLEMENTED();
diff --git a/services/device/public/cpp/generic_sensor/sensor_reading.h b/services/device/public/cpp/generic_sensor/sensor_reading.h
index 699f92d..da46949 100644
--- a/services/device/public/cpp/generic_sensor/sensor_reading.h
+++ b/services/device/public/cpp/generic_sensor/sensor_reading.h
@@ -74,7 +74,7 @@
   // PRESSURE:
   // values[0]: atmospheric pressure in hPa (millibar).
   //
-  // ABSOLUTE_ORIENTATION:
+  // ABSOLUTE_ORIENTATION_QUATERNION:
   // values[0]: x value of a quaternion representing the orientation of the
   // device in 3D space.
   // values[1]: y value of a quaternion representing the orientation of the
@@ -84,7 +84,7 @@
   // values[3]: w value of a quaternion representing the orientation of the
   // device in 3D space.
   //
-  // RELATIVE_ORIENTATION:
+  // RELATIVE_ORIENTATION_QUATERNION:
   // (Identical to ABSOLUTE_ORIENTATION except that it doesn't use the
   // geomagnetic field.)
   // values[0]: x value of a quaternion representing the orientation of the
diff --git a/services/device/public/interfaces/sensor.mojom b/services/device/public/interfaces/sensor.mojom
index 11370a6..f3c8045 100644
--- a/services/device/public/interfaces/sensor.mojom
+++ b/services/device/public/interfaces/sensor.mojom
@@ -16,9 +16,9 @@
   GYROSCOPE,
   MAGNETOMETER,
   PRESSURE,
-  ABSOLUTE_ORIENTATION,
-  RELATIVE_ORIENTATION,
-  LAST = RELATIVE_ORIENTATION // Note: LAST is also equal to the types count.
+  ABSOLUTE_ORIENTATION_QUATERNION,
+  RELATIVE_ORIENTATION_QUATERNION,
+  LAST = RELATIVE_ORIENTATION_QUATERNION // Note: LAST is also equal to the types count.
 };
 
 // Reporting mode supported by the Sensor.
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 0c4c151..7ceb5aa5 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -224,6 +224,10 @@
 #define SK_SUPPORT_LEGACY_BILERP_IGNORING_HACK
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_MASK_BLUR
+#define SK_SUPPORT_LEGACY_MASK_BLUR
+#endif
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 78405b7..7406636 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -30,7 +30,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -187,7 +187,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -659,7 +659,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -738,7 +738,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -816,7 +816,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -894,7 +894,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1284,7 +1284,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1323,7 +1323,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1362,7 +1362,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1401,7 +1401,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1440,7 +1440,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1498,6 +1498,36 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "4",
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -1518,7 +1548,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -2803,6 +2833,38 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "KTU84Z",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -3996,6 +4058,38 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "LMY48I",
+              "device_type": "hammerhead"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -5381,6 +5475,38 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "LMY49B",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -5479,7 +5605,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -5642,7 +5768,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6477,7 +6603,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6557,7 +6683,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6637,7 +6763,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6677,7 +6803,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6837,7 +6963,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6877,7 +7003,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6917,7 +7043,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6957,7 +7083,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6997,7 +7123,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -7101,6 +7227,37 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "4",
+              "device_os": "MMB29Q",
+              "device_type": "bullhead"
+            }
+          ],
+          "hard_timeout": 960,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
@@ -7121,7 +7278,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -8383,6 +8540,38 @@
         "test": "unit_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "MRA58Z",
+              "device_type": "flo"
+            }
+          ],
+          "expiration": 10800,
+          "hard_timeout": 300,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "viz_unittests"
+      },
+      {
         "merge": {
           "args": [
             "--bucket",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2217e8b..7958a7a 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -481,6 +481,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -849,6 +855,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1207,6 +1219,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index dccc7c8..7a53df89 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -481,11 +481,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -495,7 +496,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "components_unittests"
       },
@@ -520,7 +522,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "6",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -535,7 +537,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 6
         },
         "test": "content_browsertests"
       },
@@ -1196,11 +1199,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -1210,7 +1214,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "net_unittests"
       },
@@ -1510,7 +1515,38 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "hard_timeout": 900,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -1526,7 +1562,7 @@
             }
           ]
         },
-        "test": "unit_tests"
+        "test": "viz_unittests"
       },
       {
         "args": [
@@ -2085,11 +2121,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -2099,7 +2136,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "components_unittests"
       },
@@ -2124,7 +2162,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "6",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -2139,7 +2177,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 6
         },
         "test": "content_browsertests"
       },
@@ -2800,11 +2839,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -2814,7 +2854,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "net_unittests"
       },
@@ -3114,7 +3155,38 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "hard_timeout": 900,
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ]
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "android_devices": "1",
               "device_os": "KTU84P",
               "device_type": "hammerhead"
             }
@@ -3130,7 +3202,7 @@
             }
           ]
         },
-        "test": "unit_tests"
+        "test": "viz_unittests"
       },
       {
         "args": [
@@ -4198,6 +4270,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -4882,6 +4960,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
@@ -5265,6 +5349,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index dfcf46b..8cbb9f8d 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -386,6 +386,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -824,6 +830,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -1272,6 +1284,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
@@ -1679,6 +1697,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -2067,6 +2091,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 052b4ec..8fc1420 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -600,6 +600,12 @@
           "can_use_on_swarming_builders": true
         },
         "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
       }
     ]
   },
@@ -911,6 +917,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1234,6 +1246,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1509,6 +1527,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -1732,6 +1756,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 9c17388d..0ceb38a 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -3515,6 +3515,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build249-m4--device6",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build249-m4--device6",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device3",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device3",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build249-m4--device2",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build249-m4--device2",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device4",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build248-m4--device4",
+              "os": "Android",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -8747,6 +8983,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:22b1",
+              "id": "build140-b1",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:22b1",
+              "id": "build140-b1",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:22b1",
+              "id": "build143-b1",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:22b1",
+              "id": "build143-b1",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -13756,6 +14110,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:9874",
+              "id": "build204-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:9874",
+              "id": "build204-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:9874",
+              "id": "build207-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:9874",
+              "id": "build207-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf-fyi"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 0949bf0..51bc228 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -3560,6 +3560,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build14-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -8412,6 +8648,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build74-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -11534,6 +12006,126 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build165-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build164-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build165-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build165-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -15748,6 +16340,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build16-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -18870,6 +19698,126 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build113-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build112-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build113-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build113-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -23084,6 +24032,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build10-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -27936,6 +29120,242 @@
       },
       {
         "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build18-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build18-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build18-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.large_profile.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.large_profile.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build18-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "startup.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "startup.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "storage.indexeddb_endure",
           "-v",
           "--upload-results",
@@ -33091,6 +34511,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0166",
+              "id": "build105-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0166",
+              "id": "build105-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0166",
+              "id": "build106-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0166",
+              "id": "build106-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -38100,6 +39638,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build161-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build161-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build162-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build162-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -43109,6 +44765,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build126-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build126-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build127-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build127-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -48098,6 +49872,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build27-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a26",
+              "id": "build28-b1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -53107,6 +54999,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build131-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build131-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build132-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build132-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -58116,6 +60126,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0d26",
+              "id": "build7-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0d26",
+              "id": "build7-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0d26",
+              "id": "build30-b4",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0d26",
+              "id": "build30-b4",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -63105,6 +65233,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build120-b1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build120-b1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build180-b4",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build180-b4",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -68114,6 +70360,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0534",
+              "id": "build135-m1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0534",
+              "id": "build135-m1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0534",
+              "id": "build136-m1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0534",
+              "id": "build136-m1",
+              "os": "Windows-10-10240",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -73183,6 +75547,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build104-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build104-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build105-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build105-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -78232,6 +80714,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build167-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build167-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build168-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build168-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -83281,6 +85881,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "id": "build95-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "id": "build95-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "id": "build96-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "id": "build96-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -88310,6 +91028,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build188-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build188-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build189-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build189-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -93339,6 +96175,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build141-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build141-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build142-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build142-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
@@ -98388,6 +101342,124 @@
       },
       {
         "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build146-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.cold.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.cold.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build146-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=release_x64"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build147-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "start_with_url.warm.startup_pages",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_url.warm.startup_pages.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build147-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
           "startup.cold.blank_page",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 2cf5a44..de45ea8 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -455,6 +455,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
@@ -1015,6 +1021,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ]
@@ -1540,6 +1552,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -2005,6 +2023,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 2a4d679..b79229b 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1069,6 +1069,10 @@
     "label": "//ui/views:views_unittests",
     "type": "windowed_test_launcher",
   },
+  "viz_unittests": {
+    "label": "//components/viz:viz_unittests",
+    "type": "windowed_test_launcher",
+  },
   "vr_common_unittests": {
     "label": "//chrome/browser/android/vr_shell:vr_common_unittests",
     "type": "console_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index e61a712..edd4855 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -16877,7 +16877,6 @@
 crbug.com/591099 inspector/help/release-note-unit.html [ Crash Failure ]
 crbug.com/591099 inspector/help/release-note.html [ Crash Failure ]
 crbug.com/591099 inspector/import-open-inspector.html [ Failure ]
-crbug.com/591099 inspector/initial-modules-load.html [ Failure ]
 crbug.com/591099 inspector/input-event-warning.html [ Failure ]
 crbug.com/591099 inspector/inspected-objects-not-overriden.html [ Failure ]
 crbug.com/591099 inspector/inspector-backend-commands.html [ Failure ]
@@ -16886,6 +16885,10 @@
 crbug.com/591099 inspector/layers/layer-replay-scale.html [ Crash Failure ]
 crbug.com/591099 inspector/local-object-properties-section.html [ Failure ]
 crbug.com/591099 inspector/local-object.html [ Failure ]
+crbug.com/591099 inspector/modules-load-elements.html [ Failure ]
+crbug.com/591099 inspector/modules-load-initial.html [ Failure ]
+crbug.com/591099 inspector/modules-load-network.html [ Failure ]
+crbug.com/591099 inspector/modules-load-source.html [ Failure ]
 crbug.com/591099 inspector/network/network-cookies-pane.html [ Crash Failure ]
 crbug.com/591099 inspector/network/network-domain-filter.html [ Failure ]
 crbug.com/591099 inspector/network/network-filmstrip-overview-showing.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 18a99ab7..7c76b9c9 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -2816,11 +2816,14 @@
 Bug(none) inspector/file-system-project.html [ Failure ]
 Bug(none) inspector/geolocation-emulation-tests.html [ Timeout ]
 Bug(none) inspector/import-open-inspector.html [ Timeout ]
-Bug(none) inspector/initial-modules-load.html [ Timeout ]
 Bug(none) inspector/input-event-warning.html [ Timeout ]
 Bug(none) inspector/inspected-objects-not-overriden.html [ Timeout ]
 Bug(none) inspector/layers/layer-replay-scale.html [ Timeout ]
 Bug(none) inspector/layers/layers-3d-view-hit-testing.html [ Timeout ]
+Bug(none) inspector/modules-load-elements.html [ Timeout ]
+Bug(none) inspector/modules-load-initial.html [ Timeout ]
+Bug(none) inspector/modules-load-network.html [ Timeout ]
+Bug(none) inspector/modules-load-source.html [ Timeout ]
 Bug(none) inspector/network/network-cookies-pane.html [ Timeout ]
 Bug(none) inspector/network/network-json-parser.html [ Timeout ]
 Bug(none) inspector/profiler/cpu-profiler-save-load.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index cbf0890..619fdd7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -245,9 +245,6 @@
 crbug.com/711807 external/wpt/css/CSS2/normal-flow/width-inherit-001.xht [ Skip ]
 
 #### third_party/WebKit/LayoutTests/overflow
-#### Passed: 6
-#### Failed: 3
-crbug.com/723788 overflow/overflow-transform-002.html [ Failure ]
 crbug.com/724697 overflow/overflow-basic-002.html [ Failure ]
 crbug.com/724701 overflow/overflow-basic-004.html [ Failure ]
 
@@ -889,6 +886,8 @@
 # Text::inDocument() returns false but should not.
 crbug.com/264138 dom/legacy_dom_conformance/xhtml/level3/core/nodecomparedocumentposition38.xhtml [ Failure ]
 
+crbug.com/736676 virtual/enable_wasm_streaming/http/tests/wasm_streaming/wasm_response_apis.html [ Pass Crash ]
+
 crbug.com/410145 [ Win ] fast/table/column-in-inline.html [ Failure ]
 crbug.com/410145 [ Win ] virtual/mojo-loading/fast/table/column-in-inline.html [ Failure ]
 crbug.com/411164 [ Win ] http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Pass ]
@@ -1864,6 +1863,7 @@
 crbug.com/724251 virtual/threaded/animations/svg-attribute-interpolation/svg-startOffset-interpolation.html [ Failure Pass ]
 
 crbug.com/739965 inspector/console/console-log-linkify-stack-in-errors.html [ NeedsManualRebaseline ]
+crbug.com/739965 fast/events/window-onerror-12.html [ NeedsManualRebaseline ]
 
 crbug.com/736050 external/wpt/IndexedDB/idbcursor_advance_index.htm [ Pass Failure ]
 crbug.com/736050 external/wpt/IndexedDB/idbcursor-continue-exception-order.htm [ Pass Failure ]
@@ -2614,6 +2614,241 @@
 
 # ====== Random order flaky tests end here ======
 
+# ====== Tests from enabling .any.js/.worker.js tests begin here ======
+crbug.com/709227 external/wpt/FileAPI/idlharness.worker.html [ Failure ]
+crbug.com/709227 external/wpt/IndexedDB/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_bits.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/derive_bits_keys/ecdh_keys.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/digest/digest.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/encrypt_decrypt/aes_cbc.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/encrypt_decrypt/aes_ctr.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/encrypt_decrypt/aes_gcm.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/encrypt_decrypt/rsa.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_AES-KW.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_ECDH.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_ECDSA.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_HMAC.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_AES-CBC.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_AES-CTR.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_AES-GCM.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_AES-KW.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_ECDH.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_ECDSA.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_HMAC.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_RSA-PSS.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/idlharness.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/import_export/ec_importKey.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/sign_verify/ecdsa.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/sign_verify/hmac.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/sign_verify/rsa_pkcs.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/sign_verify/rsa_pss.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.worker.html [ Failure ]
+crbug.com/709227 external/wpt/WebIDL/ecmascript-binding/es-exceptions/constructor-object.worker.html [ Failure ]
+crbug.com/709227 external/wpt/background-fetch/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-count-label-conversion.any.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-count-label-conversion.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-time-label-conversion.any.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-time-label-conversion.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-timeline-timelineEnd-historical.any.html [ Failure ]
+crbug.com/709227 external/wpt/console/console-timeline-timelineEnd-historical.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/css/geometry-1/DOMMatrix-css-string.worker.html [ Failure ]
+crbug.com/709227 external/wpt/css/geometry-1/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/basic/request-upload.any.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/basic/request-upload.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/basic/scheme-about.any.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/basic/scheme-about.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-redirect.any.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-redirect.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-referrer.any.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-referrer.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-star.any.html [ Failure ]
+crbug.com/709227 external/wpt/fetch/api/cors/cors-preflight-star.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/html/browsers/history/the-location-interface/per-global.window.html [ Failure ]
+crbug.com/709227 external/wpt/html/dom/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_isindex.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_isindex.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_isindex.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_menuitem-element.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_menuitem-element.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_menuitem-element.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_template.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_template.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_template.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests19.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests19.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests19.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests2.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests2.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests2.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests25.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests25.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_tests25.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_webkit02.html?run_type=uri [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_webkit02.html?run_type=write [ Failure ]
+crbug.com/709227 external/wpt/html/syntax/parsing/html5lib_webkit02.html?run_type=write_single [ Failure ]
+crbug.com/709227 external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.html [ Failure ]
+crbug.com/709227 external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-errorevent.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-1.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-2.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-3.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-4.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-6.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-7.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-8.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsl-9.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-1.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-2.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-3.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-4.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-6.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-7.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-8.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-hsla-9.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-1.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-2.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-3.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-4.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgb-6.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-1.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-3.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-4.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-5.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.fillStyle.parse.css-color-4-rgba-6.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.gradient.radial.outside3.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.arc.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.closed.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.curve.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.line.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/path-objects/2d.path.stroke.prune.rect.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/pixel-manipulation/2d.imageData.create2.nonfinite.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/pixel-manipulation/2d.imageData.get.nonfinite.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/pixel-manipulation/2d.imageData.get.tiny.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/pixel-manipulation/2d.imageData.put.nonfinite.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/2d.getcontext.extraargs.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.getcontext.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.idl.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.em.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.empty.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.junk.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.minus.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.onlyspace.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.percent.worker.html [ Failure ]
+crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.trailingjunk.worker.html [ Failure ]
+crbug.com/709227 external/wpt/performance-timeline/po-disconnect.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/performance-timeline/po-getentries.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/performance-timeline/po-mark-measure.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/performance-timeline/po-observe.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/storage/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/url/historical.any.html [ Failure ]
+crbug.com/709227 external/wpt/url/historical.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/url/interfaces.any.html [ Failure ]
+crbug.com/709227 external/wpt/url/interfaces.any.worker.html [ Failure ]
+crbug.com/709227 external/wpt/url/toascii.window.html [ Failure ]
+crbug.com/709227 external/wpt/user-timing/invoke_with_timing_attributes.worker.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/closing-handshake/002.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/closing-handshake/003.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/closing-handshake/004.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/002.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/002.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/006.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/009.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/010.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/010.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/011.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/011.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/013.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/014.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/016.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/018.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/019.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/020.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/constructor/022.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/001.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/002.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/003.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/004.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/005.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/005.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/006.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/007.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/cookies/007.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/CloseEvent/clean-close.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-getting.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/close/close-connecting.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/close/close-connecting.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/close/close-nested.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/close/close-nested.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/events/016.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/readyState/003.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/readyState/003.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/readyState/006.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/readyState/007.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/readyState/008.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/007.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/008.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/009.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/011.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/012.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/keeping-connection-open/001.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/opening-handshake/002.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/opening-handshake/003.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/opening-handshake/005.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/unload-a-document/001.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/unload-a-document/001.html?wss [ Failure ]
+crbug.com/709227 external/wpt/websockets/unload-a-document/002.html [ Failure ]
+crbug.com/709227 external/wpt/websockets/unload-a-document/002.html?wss [ Failure ]
+crbug.com/709227 external/wpt/workers/constructors/Worker/DedicatedWorkerGlobalScope-members.worker.html [ Failure ]
+crbug.com/709227 external/wpt/workers/constructors/Worker/expected-self-properties.worker.html [ Failure ]
+crbug.com/709227 external/wpt/workers/interfaces.worker.html [ Failure ]
+crbug.com/709227 external/wpt/workers/interfaces/WorkerUtils/importScripts/002.worker.html [ Failure ]
+crbug.com/709227 external/wpt/workers/semantics/interface-objects/001.worker.html [ Failure ]
+crbug.com/709227 external/wpt/workers/semantics/interface-objects/002.worker.html [ Failure ]
+crbug.com/709227 http/tests/inspector-protocol/network/disable-interception-midway.html [ Failure ]
+
+# Timeouts
+crbug.com/709227 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html [ Timeout ]
+crbug.com/709227 external/wpt/websockets/binary/001.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/binary/002.html?wss [ Failure Timeout ]
+crbug.com/709227 external/wpt/websockets/binary/004.html?wss [ Failure Timeout ]
+crbug.com/709227 external/wpt/websockets/binary/005.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/extended-payload-length.html?wss [ Failure Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-arraybuffer.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-blob.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-large.html?wss [ Failure Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/bufferedAmount/bufferedAmount-unicode.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/events/018.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/005.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/006.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/interfaces/WebSocket/send/010.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/websockets/opening-handshake/003-sets-origin.worker.html [ Timeout ]
+crbug.com/709227 external/wpt/websockets/opening-handshake/005.html?wss [ Timeout ]
+crbug.com/709227 external/wpt/workers/nested_worker.worker.html [ Timeout ]
+
+# Crashes
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
+
+# ====== Tests from enabling .any.js/.worker.js tests end here ========
+
 # ====== Begin of display: contents tests ======
 
 crbug.com/657748 external/wpt/css/css-display-3/display-contents-before-after-002.html [ Failure ]
@@ -2831,6 +3066,15 @@
 crbug.com/737959 http/tests/misc/video-poster-image-load-outlives-gc-without-crashing.html [ Failure Pass Crash ]
 crbug.com/737959 virtual/off-main-thread-fetch/http/tests/misc/video-poster-image-load-outlives-gc-without-crashing.html [ Failure Pass Crash ]
 
+# Awaiting rebaseline after skia roll.
+crbug.com/739559 virtual/gpu-rasterization/images/color-profile-background-image-space.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/color-profile-svg-fill-text.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/color-profile-svg.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/cross-fade-background-size.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/cross-fade-overflow-position.html [ Failure Pass ]
+crbug.com/739559 virtual/gpu-rasterization/images/cross-fade-tiled.html [ Failure Pass ]
+
 # These tests are failing on Mac-10.12 when using an Intel GPU.
 crbug.com/736177 [ Mac ] css2.1/t1202-counter-04-b.html [ Failure Pass ]
 crbug.com/736177 [ Mac ] css2.1/t1202-counters-04-b.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical-expected.txt
deleted file mode 100644
index d362658c..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/geometry-1/historical-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-This is a testharness.js-based test.
-PASS DOMMatrixReadOnly scaleNonUniform must be nuked 
-PASS DOMMatrix scaleNonUniformSelf must be nuked 
-PASS DOMMatrix multiplyBy must be nuked 
-PASS DOMMatrix preMultiplyBy must be nuked 
-PASS DOMMatrix translateBy must be nuked 
-PASS DOMMatrix scaleBy must be nuked 
-PASS DOMMatrix scale3dBy must be nuked 
-PASS DOMMatrix scaleNonUniformBy must be nuked 
-PASS DOMMatrix rotateBy must be nuked 
-PASS DOMMatrix rotateFromVectorBy must be nuked 
-PASS DOMMatrix rotateAxisAngleBy must be nuked 
-PASS DOMMatrix skewXBy must be nuked 
-PASS DOMMatrix skewYBy must be nuked 
-PASS DOMMatrix fromString static member must be nuked 
-PASS DOMMatrixReadOnly fromString static member must be nuked 
-PASS DOMMatrixReadOnly scale number of required arguments 
-PASS DOMMatrix scaleSelf number of required arguments 
-PASS DOMMatrixReadOnly translate number of required arguments 
-PASS DOMMatrixReadOnly scale3d number of required arguments 
-PASS DOMMatrixReadOnly rotateFromVector number of required arguments 
-PASS DOMMatrixReadOnly rotateAxisAngle number of required arguments 
-PASS DOMMatrixReadOnly skewX number of required arguments 
-PASS DOMMatrixReadOnly skewY number of required arguments 
-PASS DOMMatrix translateSelf number of required arguments 
-PASS DOMMatrix scale3dSelf number of required arguments 
-PASS DOMMatrix rotateFromVectorSelf number of required arguments 
-PASS DOMMatrix rotateAxisAngleSelf number of required arguments 
-PASS DOMMatrix skewXSelf number of required arguments 
-PASS DOMMatrix skewYSelf number of required arguments 
-PASS DOMPointReadOnly matrixTransform number of required arguments 
-PASS DOMMatrixReadOnly multiply number of required arguments 
-PASS DOMMatrix multiplySelf number of required arguments 
-PASS DOMMatrix preMultiplySelf number of required arguments 
-PASS CSSMatrix must be nuked 
-PASS DOMMatrixImmutable must be nuked 
-FAIL ClientRect must be nuked assert_false: expected false got true
-FAIL ClientRectList must be nuked assert_false: expected false got true
-PASS WebKitPoint must be nuked 
-PASS MSCSSMatrix must be nuked 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/cssom-getBoundingClientRect-002-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/cssom-view/cssom-getBoundingClientRect-002-expected.txt
deleted file mode 100644
index cda258b..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/cssom-view/cssom-getBoundingClientRect-002-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL getBoundingClientRect on a newly-created Element not yet inserted into the DOM should return an all-zeroes DOMRect assert_equals: DOMRect's x should be zero expected (number) 0 but got (undefined) undefined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
index e9e146b2..bda480b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 5193 tests; 4986 PASS, 207 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 5193 tests; 4987 PASS, 206 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver 
 PASS Document interface: attribute domain 
 PASS Document interface: attribute referrer 
@@ -592,7 +592,7 @@
 PASS HTMLElement interface: attribute onmouseout 
 PASS HTMLElement interface: attribute onmouseover 
 PASS HTMLElement interface: attribute onmouseup 
-FAIL HTMLElement interface: attribute onwheel assert_own_property: expected property "onwheel" missing
+PASS HTMLElement interface: attribute onwheel 
 PASS HTMLElement interface: attribute onpause 
 PASS HTMLElement interface: attribute onplay 
 PASS HTMLElement interface: attribute onplaying 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
index f2866e5..8e87cc47 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/scripting/events/event-handler-all-global-events-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 300 tests; 291 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 300 tests; 292 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS onabort: must be on the appropriate locations for GlobalEventHandlers 
 PASS onabort: the default value must be null 
 PASS onabort: the content attribute must be compiled into a function as the corresponding property 
@@ -205,7 +205,7 @@
 PASS onmouseup: the content attribute must be compiled into a function as the corresponding property 
 PASS onmouseup: the content attribute must execute when an event is dispatched 
 PASS onmouseup: dispatching an Event at a <meta> element must trigger element.onmouseup 
-FAIL onwheel: must be on the appropriate locations for GlobalEventHandlers assert_true: HTMLElement has an own property named "onwheel" expected true got false
+PASS onwheel: must be on the appropriate locations for GlobalEventHandlers 
 PASS onwheel: the default value must be null 
 PASS onwheel: the content attribute must be compiled into a function as the corresponding property 
 PASS onwheel: the content attribute must execute when an event is dispatched 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument-expected.txt
index f53a6c74..200e6bdc 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument-expected.txt
@@ -3,12 +3,11 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS clientRects.__proto__ is ClientRectList.prototype
 PASS clientRects.length is 3
 PASS clientRects.item(0) is not null
 PASS clientRects.item(1) is not null
 PASS clientRects.item(2) is not null
-PASS clientRects.item() threw exception TypeError: Failed to execute 'item' on 'ClientRectList': 1 argument required, but only 0 present..
+PASS clientRects.item() threw exception TypeError: Failed to execute 'item' on 'DOMRectList': 1 argument required, but only 0 present..
 PASS clientRects.item(-4294967294) is clientRects.item(2)
 PASS clientRects.item(3) is null
 PASS clientRects.item(999) is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument.html b/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument.html
index 644642a..824b04f 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/Element/client-rect-list-argument.html
@@ -24,13 +24,11 @@
 description("Tests that the ClientRectList.item() argument is correctly validated.");
 
 var clientRects = document.getElementById("testElement").getClientRects();
-shouldBe("clientRects.__proto__", "ClientRectList.prototype");
-
 shouldBe("clientRects.length", "3");
 shouldNotBe("clientRects.item(0)", "null");
 shouldNotBe("clientRects.item(1)", "null");
 shouldNotBe("clientRects.item(2)", "null");
-shouldThrow("clientRects.item()", '"TypeError: Failed to execute \'item\' on \'ClientRectList\': 1 argument required, but only 0 present."');
+shouldThrow("clientRects.item()", '"TypeError: Failed to execute \'item\' on \'DOMRectList\': 1 argument required, but only 0 present."');
 shouldBe("clientRects.item(-4294967294)", "clientRects.item(2)"); // -4294967294 wraps to 2.
 
 // According to the specification, we should throw an IndexSizeError exception when index is
diff --git a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
index fb226662..b56484b 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers-expected.txt
@@ -703,5 +703,16 @@
 PASS Enumerate Document.onwaiting 
 PASS Set Window.onwaiting 
 PASS Enumerate Window.onwaiting 
+PASS No Element.onwheel 
+PASS Set HTMLElement.onwheel 
+PASS Enumerate HTMLElement.onwheel 
+PASS Reflect HTMLElement.onwheel 
+PASS Set SVGElement.onwheel 
+PASS Enumerate SVGElement.onwheel 
+PASS Reflect SVGElement.onwheel 
+PASS Set Document.onwheel 
+PASS Enumerate Document.onwheel 
+PASS Set Window.onwheel 
+PASS Enumerate Window.onwheel 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
index 4417478..0092151 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/global-event-handlers.html
@@ -69,7 +69,8 @@
     "ontouchmove",
     "ontouchstart",
     "onvolumechange",
-    "onwaiting"
+    "onwaiting",
+    "onwheel"
 ].forEach(function(attribute) {
     test(function() {
         assert_false(attribute in getObject("Element"));
diff --git a/third_party/WebKit/LayoutTests/fast/events/window-onerror-12-expected.txt b/third_party/WebKit/LayoutTests/fast/events/window-onerror-12-expected.txt
index 31554f8..5f7994c 100644
--- a/third_party/WebKit/LayoutTests/fast/events/window-onerror-12-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/window-onerror-12-expected.txt
@@ -6,30 +6,30 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 12, Column: 37)
+window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 12, Column: 38)
 Stack Trace:
 TypeError: Cannot read property 'mu' of null
-    at HTMLButtonElement.onclick window-onerror-12.html:12:37
+    at HTMLButtonElement.onclick window-onerror-12.html:12:38
     at window-onerror-12.html:33:24
 
 Returning 'true': the error should not be reported in the console as an unhandled exception.
 
 
 
-window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 35, Column: 18)
+window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 35, Column: 19)
 Stack Trace:
 TypeError: Cannot read property 'mu' of null
-    at HTMLButtonElement.onclick window-onerror-12.html:35:18
+    at HTMLButtonElement.onclick window-onerror-12.html:35:19
     at window-onerror-12.html:33:24
 
 Returning 'true': the error should not be reported in the console as an unhandled exception.
 
 
 
-window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 35, Column: 18)
+window.onerror: "Uncaught TypeError: Cannot read property 'mu' of null" at window-onerror-12.html (Line: 35, Column: 19)
 Stack Trace:
 TypeError: Cannot read property 'mu' of null
-    at HTMLButtonElement.onclick window-onerror-12.html:35:18
+    at HTMLButtonElement.onclick window-onerror-12.html:35:19
     at window-onerror-12.html:33:24
 
 Returning 'true': the error should not be reported in the console as an unhandled exception.
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/cached-position-called-once.html b/third_party/WebKit/LayoutTests/geolocation-api/cached-position-called-once.html
index 0c77166..cd2eb15c 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/cached-position-called-once.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/cached-position-called-once.html
@@ -38,7 +38,7 @@
     setTimeout(fn, milliseconds);
 }
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(31.478, -0.166, 100);
     mock.setGeolocationPermission(true);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
index 7b533bd8..f90c8345 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-deleted-context.html b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-deleted-context.html
index 006b85e..d92ae59 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-deleted-context.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-deleted-context.html
@@ -21,7 +21,7 @@
 }
 
 var iframe = document.createElement('iframe');
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(51.478, -0.166, 100);
     iframe.src = 'resources/callback-to-deleted-context-inner1.html';
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/clear-watch-invalid-id-crash.html b/third_party/WebKit/LayoutTests/geolocation-api/clear-watch-invalid-id-crash.html
index 11efa326..3d4ed4b 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/clear-watch-invalid-id-crash.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/clear-watch-invalid-id-crash.html
@@ -13,7 +13,7 @@
   debug('This test can not run without testRunner');
 
 document.body.onload = function() {
-    geolocationServiceMock.then(mock => {
+    geolocationMock.then(mock => {
         mock.setGeolocationPermission(true);
         mock.setGeolocationPosition(51.478, -0.166, 100);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html b/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html
index 6db76c2..28fdf4d 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html
@@ -24,7 +24,7 @@
 var currentTestIndex = -1;
 var globalCoordinates = null;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
 
     function runNextTest()
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed-for-multiple-requests.html b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed-for-multiple-requests.html
index 4d0f3ae..861b15e7 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed-for-multiple-requests.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed-for-multiple-requests.html
@@ -9,7 +9,7 @@
 <script>
 description("Tests that when multiple requests are waiting for permission, no callbacks are invoked until permission is allowed.");
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
     var permissionSet = false;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html
index c6215a62..dcb195fe 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html
@@ -9,7 +9,7 @@
 <script>
 description("Tests that when a position is available, no callbacks are invoked until permission is allowed.");
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
     var permissionSet = false;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied-for-multiple-requests.html b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied-for-multiple-requests.html
index 36190fa..0fe4f4c 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied-for-multiple-requests.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied-for-multiple-requests.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
     var permissionSet = false;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html
index 87347e00..ea04384 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
     var permissionSet = false;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html
index b14bacb..b175301 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html
@@ -11,7 +11,7 @@
 
 var iframe = document.createElement('iframe');
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-permission-denied.html b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-permission-denied.html
index 997061c..17451c44 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-permission-denied.html
@@ -42,7 +42,7 @@
 }
 
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     // Prime the Geolocation instance by denying permission. This makes sure that we execute the
     // same code path for both preemptive and non-preemptive permissions policies.
     mock.setGeolocationPermission(false);
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
index 899a3fc..f74a9be 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
@@ -31,7 +31,7 @@
     }, 100);
 }
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html b/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html
index e4d27e0..07b9cd2 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html
@@ -9,7 +9,7 @@
 <script>
 description("This tests removing the watcher from an error callback does not causes assertions.");
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPositionUnavailableError("debug");
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/error-service-connection-error.html b/third_party/WebKit/LayoutTests/geolocation-api/error-service-connection-error.html
index 4ecf9c4..acab5ff5 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/error-service-connection-error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/error-service-connection-error.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
   mock.setGeolocationPermission(true);
   mock.rejectGeolocationConnections();
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/error.html b/third_party/WebKit/LayoutTests/geolocation-api/error.html
index 73ddb28c..3843736 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/error.html
@@ -13,7 +13,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
   mock.setGeolocationPermission(true);
   mock.setGeolocationPositionUnavailableError(mockMessage);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html b/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
index 983dec7..fe111c9 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
@@ -33,7 +33,7 @@
     shouldBe('error.message', 'mockMessage');
 }
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html b/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
index f288f42..887e4805 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
@@ -17,7 +17,7 @@
 var watchCallbackInvoked = false;
 var oneShotCallbackInvoked = false;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html b/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html
index 235ac4ef..adccc86a7 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html
@@ -12,7 +12,7 @@
 if (!window.testRunner)
   debug('This test can not run without testRunner');
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
 
     location = "../fast/events/resources/onunload-single-alert-success.html";
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-clear-watch.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-clear-watch.html
index 4a121de..198895fe 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-clear-watch.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
 
     // Prime the Geolocation instance by denying permission.
     mock.setGeolocationPermission(false);
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-error.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-error.html
index 32fb13ca..d5beaa1 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-error.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(false);
     mock.setGeolocationPosition(51.478, -0.166, 100);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-success.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-success.html
index 54f6336a..d60b4fa89 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-success.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-already-success.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
 
     // Prime the Geolocation instance by denying permission.
     mock.setGeolocationPermission(false);
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-stops-watches.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-stops-watches.html
index 849f2a11..51673f6 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-stops-watches.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied-stops-watches.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
 
     // Configure the mock Geolocation service to report a position to cause permission
     // to be requested, then deny it.
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
index 28a54ee..b35dc51 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
 
     mock.setGeolocationPermission(false);
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-service-connection-error.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-service-connection-error.html
index 63aed1b..dcb5088 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-service-connection-error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-service-connection-error.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
 
     mock.rejectPermissionConnections();
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/position-string.html b/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
index 665d4f1a..8e15f53 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
index 2034b9ec..b843a4f 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
@@ -13,7 +13,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPositionUnavailableError(mockMessage);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html
index ce70daba..b678e4e 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(false);
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
index 94e91da2..c6af991 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/resources/callback-to-remote-context-inner.html b/third_party/WebKit/LayoutTests/geolocation-api/resources/callback-to-remote-context-inner.html
index eb521d2f..dadae4cf 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/resources/callback-to-remote-context-inner.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/resources/callback-to-remote-context-inner.html
@@ -6,7 +6,7 @@
     <script src="geolocation-mock.js"></script>
     <script>
       function init() {
-          geolocationServiceMock.then(mock => {
+          geolocationMock.then(mock => {
               mock.setGeolocationPermission(true);
               mock.setGeolocationPosition(51.478, -0.166, 100);
               window.parent.onIframeReady()
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js b/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js
index a7ae135..8300eac 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js
+++ b/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js
@@ -1,12 +1,12 @@
 /*
- * geolocation-mock contains a mock implementation of GeolocationService and
+ * geolocation-mock contains a mock implementation of Geolocation and
  * PermissionService.
  */
 
 "use strict";
 
-let geolocationServiceMock = loadMojoModules(
-    'geolocationServiceMock',
+let geolocationMock = loadMojoModules(
+    'geolocationMock',
     ['device/geolocation/public/interfaces/geolocation.mojom',
      'device/geolocation/public/interfaces/geoposition.mojom',
      'third_party/WebKit/public/platform/modules/permissions/permission.mojom',
@@ -16,10 +16,10 @@
   let [geolocation, geoposition, permission, permissionStatus, bindings] =
       mojo.modules;
 
-  class GeolocationServiceMock {
+  class GeolocationMock {
     constructor(interfaceProvider) {
       interfaceProvider.addInterfaceOverrideForTesting(
-          geolocation.GeolocationService.name,
+          geolocation.Geolocation.name,
           handle => this.connectGeolocation_(handle));
 
       interfaceProvider.addInterfaceOverrideForTesting(
@@ -54,7 +54,7 @@
       this.rejectGeolocationConnections_ = false;
 
       this.geolocationBindingSet_ = new bindings.BindingSet(
-          geolocation.GeolocationService);
+          geolocation.Geolocation);
       this.permissionBindingSet_ = new bindings.BindingSet(
           permission.PermissionService);
     }
@@ -81,7 +81,7 @@
     }
 
     /**
-     * A mock implementation of GeolocationService.queryNextPosition(). This
+     * A mock implementation of Geolocation.queryNextPosition(). This
      * returns the position set by a call to setGeolocationPosition() or
      * setGeolocationPositionUnavailableError().
      */
@@ -183,5 +183,5 @@
     }
 
   }
-  return new GeolocationServiceMock(mojo.frameInterfaces);
+  return new GeolocationMock(mojo.frameInterfaces);
 });
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/resources/remove-remote-context-in-error-callback-crash-inner.html b/third_party/WebKit/LayoutTests/geolocation-api/resources/remove-remote-context-in-error-callback-crash-inner.html
index cd99789..ba40d53 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/resources/remove-remote-context-in-error-callback-crash-inner.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/resources/remove-remote-context-in-error-callback-crash-inner.html
@@ -5,7 +5,7 @@
     <script src="geolocation-mock.js"></script>
     <script>
       function init() {
-          geolocationServiceMock.then(mock => {
+          geolocationMock.then(mock => {
               mock.setGeolocationPermission(false);
               window.parent.onIframeReady()
           });
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/resources/window-close-popup.html b/third_party/WebKit/LayoutTests/geolocation-api/resources/window-close-popup.html
index 1ce0718..1af8ce0 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/resources/window-close-popup.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/resources/window-close-popup.html
@@ -6,7 +6,7 @@
 var mockAccuracy = 100.0;
 
 function loadNext() {
-    geolocationServiceMock.then(mock => {
+    geolocationMock.then(mock => {
         mock.setGeolocationPermission(true);
         mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html b/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html
index abd0a38..8e00fdb3 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html
@@ -13,7 +13,7 @@
 var mockLongitude = -0.166;
 var mockAccuracy = 100;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/success.html b/third_party/WebKit/LayoutTests/geolocation-api/success.html
index 5c442ea..c77f0192 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/success.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/success.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html
index 379ef7e3..fc32cbb 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
     var watchId = navigator.geolocation.watchPosition(function() {
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
index c054ddc..b4ea562 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
     navigator.geolocation.getCurrentPosition(function(p) {
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-over-max-of-unsigned.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-over-max-of-unsigned.html
index b1c16d4..bb7bf77 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-over-max-of-unsigned.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-over-max-of-unsigned.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
index 25b6322e..4e0d684c 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
@@ -11,7 +11,7 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
     navigator.geolocation.getCurrentPosition(function(p) {
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
index 66f1fc8..fe9a15a9 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
@@ -15,7 +15,7 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude,
                                 mockLongitude,
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html b/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
index 9688561..e86bc1d4 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
@@ -18,7 +18,7 @@
 var t = null;
 var then = null;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/watch.html b/third_party/WebKit/LayoutTests/geolocation-api/watch.html
index 9e8df07..3d496d9 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watch.html
@@ -33,7 +33,7 @@
     debug('');
 }
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html
index 044b03c05..0cbbc03 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html
@@ -17,7 +17,7 @@
 var error;
 var isPageVisible = true;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
 
     debug("* Page is visible");
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
index 5dd5942..394b0f8b 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
@@ -14,7 +14,7 @@
 var watchID2;
 var watchID3;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
     watchID1 = navigator.geolocation.watchPosition(function() { });
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index c71d83c..935d93e6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -945,22 +945,27 @@
     return Promise.resolve(tempFile);
 }
 
-InspectorTest.dumpLoadedModules = function(next)
+InspectorTest.loadedModules = function()
 {
+    return self.runtime._modules.filter(module => module._loadedForTest);
+}
+
+InspectorTest.dumpLoadedModules = function(relativeTo)
+{
+    var previous = new Set(relativeTo || []);
     function moduleSorter(left, right)
     {
         return String.naturalOrderComparator(left._descriptor.name, right._descriptor.name);
     }
 
     InspectorTest.addResult("Loaded modules:");
-    var modules = self.runtime._modules;
-    modules.sort(moduleSorter);
-    for (var i = 0; i < modules.length; ++i) {
-        if (modules[i]._loadedForTest)
-            InspectorTest.addResult("    " + modules[i]._descriptor.name);
+    var loadedModules = InspectorTest.loadedModules().sort(moduleSorter);
+    for (var module of loadedModules) {
+        if (previous.has(module))
+            continue;
+        InspectorTest.addResult("    " + module._descriptor.name);
     }
-    if (next)
-        next();
+    return loadedModules;
 }
 
 InspectorTest.TimeoutMock = function()
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
index f75fda5a..6dfe0dd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/multiple-report-policies-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE ERROR: [Report Only] Refused to load the image 'ftp://blah.test/' because it violates the following Content Security Policy directive: "img-src http://* https://*".
 
 PingLoader dispatched to 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/save-report.php?test=multiple-report-policies-1'.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
index 0f6d4a39..f57ae31 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/deprecated-subresource-requests-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE WARNING: Subresource requests whose URLs contain embedded credentials (e.g. `https://user:pass@host/`) are blocked. See https://www.chromestatus.com/feature/5669008342777856 for more details.
 This is a testharness.js-based test.
 PASS Untitled 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
index 19daf055..580b2e7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/geolocation.html
@@ -10,7 +10,7 @@
 if (!window.mojo)
     console.error('This test can not run without mojo');
 
-geolocationServiceMock.then(mock => {
+geolocationMock.then(mock => {
     mock.setGeolocationPermission(true);
     mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
diff --git a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
deleted file mode 100644
index 6fc93be..0000000
--- a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
+++ /dev/null
@@ -1,185 +0,0 @@
-This test validates initial set of loaded modules.
-
-
-Running: testInitialLoad
-Loaded modules:
-    bindings
-    common
-    components
-    console_model
-    dom_extension
-    emulation
-    extensions
-    help
-    host
-    main
-    mobile_throttling
-    network_log
-    persistence
-    platform
-    product_registry
-    protocol
-    sdk
-    services
-    text_utils
-    ui
-    workspace
-
-Running: testCreateElementsPanel
-Loaded modules:
-    bindings
-    color_picker
-    common
-    components
-    console_model
-    dom_extension
-    elements
-    emulation
-    event_listeners
-    extensions
-    help
-    host
-    inline_editor
-    main
-    mobile_throttling
-    network_log
-    object_ui
-    persistence
-    platform
-    product_registry
-    protocol
-    sdk
-    services
-    text_utils
-    ui
-    workspace
-
-Running: testCreateNetworkPanel
-Loaded modules:
-    animation
-    bindings
-    cm
-    color_picker
-    common
-    components
-    console_model
-    cookie_table
-    data_grid
-    diff
-    dom_extension
-    elements
-    emulation
-    event_listeners
-    extensions
-    formatter
-    help
-    host
-    inline_editor
-    main
-    mobile_throttling
-    network
-    network_log
-    network_priorities
-    object_ui
-    perf_ui
-    persistence
-    platform
-    product_registry
-    protocol
-    sdk
-    services
-    source_frame
-    text_editor
-    text_utils
-    ui
-    workspace
-    workspace_diff
-
-Running: testShowSourcesPanel
-Loaded modules:
-    animation
-    bindings
-    cm
-    color_picker
-    common
-    components
-    console_model
-    cookie_table
-    data_grid
-    diff
-    dom_extension
-    elements
-    emulation
-    event_listeners
-    extensions
-    formatter
-    help
-    host
-    inline_editor
-    main
-    mobile_throttling
-    network
-    network_log
-    network_priorities
-    object_ui
-    perf_ui
-    persistence
-    platform
-    product_registry
-    protocol
-    quick_open
-    sdk
-    services
-    snippets
-    source_frame
-    sources
-    text_editor
-    text_utils
-    ui
-    workspace
-    workspace_diff
-
-Running: testOpenUISourceCode
-Loaded modules:
-    animation
-    bindings
-    cm
-    color_picker
-    common
-    components
-    console_model
-    cookie_table
-    data_grid
-    diff
-    dom_extension
-    elements
-    emulation
-    event_listeners
-    extensions
-    formatter
-    help
-    host
-    inline_editor
-    main
-    mobile_throttling
-    network
-    network_log
-    network_priorities
-    object_ui
-    perf_ui
-    persistence
-    platform
-    product_registry
-    protocol
-    quick_open
-    sdk
-    services
-    snippets
-    source_frame
-    sources
-    text_editor
-    text_utils
-    ui
-    workspace
-    workspace_diff
-
diff --git a/third_party/WebKit/LayoutTests/inspector/initial-modules-load.html b/third_party/WebKit/LayoutTests/inspector/initial-modules-load.html
deleted file mode 100644
index e173a8b..0000000
--- a/third_party/WebKit/LayoutTests/inspector/initial-modules-load.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<html>
-<head>
-<script src="../http/tests/inspector/inspector-test.js"></script>
-<script>
-
-function test()
-{
-    InspectorTest.runTestSuite([
-        function testInitialLoad(next)
-        {
-            InspectorTest.dumpLoadedModules(next);
-        },
-
-        function testCreateElementsPanel(next)
-        {
-            UI.inspectorView.panel("elements").then(InspectorTest.dumpLoadedModules.bind(InspectorTest, self.runtime.loadModulePromise("animation").then(next)));
-        },
-
-        function testCreateNetworkPanel(next)
-        {
-            UI.inspectorView.panel("network").then(InspectorTest.dumpLoadedModules.bind(InspectorTest, next));
-        },
-
-        function testShowSourcesPanel(next)
-        {
-            UI.inspectorView.panel("sources").then(InspectorTest.dumpLoadedModules.bind(InspectorTest, next));
-        },
-
-        function testOpenUISourceCode(next)
-        {
-            var resource;
-            InspectorTest.resourceTreeModel.forAllResources(function(r) {
-                if (r.url.indexOf("inspector-test.js") !== -1) {
-                    resource = r;
-                    return true;
-                }
-            });
-            var uiLocation = Workspace.workspace.uiSourceCodeForURL(resource.url).uiLocation(2, 1);
-            Common.Revealer.reveal(uiLocation);
-            InspectorTest.dumpLoadedModules(next);
-        }
-    ]);
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>This test validates initial set of loaded modules.</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-elements-expected.txt b/third_party/WebKit/LayoutTests/inspector/modules-load-elements-expected.txt
new file mode 100644
index 0000000..7874819
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-elements-expected.txt
@@ -0,0 +1,12 @@
+This test validates initial set of loaded modules for Elements panel.
+
+Loaded modules:
+    color_picker
+    elements
+    event_listeners
+    inline_editor
+    object_ui
+Now with animations pane
+Loaded modules:
+    animation
+
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-elements.html b/third_party/WebKit/LayoutTests/inspector/modules-load-elements.html
new file mode 100644
index 0000000..1d39eea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-elements.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script>
+async function test()
+{
+    var initialModules = InspectorTest.loadedModules();
+    await UI.inspectorView.panel("elements");
+    var elementsModules = InspectorTest.dumpLoadedModules(initialModules);
+    InspectorTest.addResult("Now with animations pane");
+    await self.runtime.loadModulePromise("animation");
+    InspectorTest.dumpLoadedModules(elementsModules);
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<p>This test validates initial set of loaded modules for Elements panel.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-initial-expected.txt b/third_party/WebKit/LayoutTests/inspector/modules-load-initial-expected.txt
new file mode 100644
index 0000000..a4b8502
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-initial-expected.txt
@@ -0,0 +1,25 @@
+This test validates initial set of loaded modules.
+
+Loaded modules:
+    bindings
+    common
+    components
+    console_model
+    dom_extension
+    emulation
+    extensions
+    help
+    host
+    main
+    mobile_throttling
+    network_log
+    persistence
+    platform
+    product_registry
+    protocol
+    sdk
+    services
+    text_utils
+    ui
+    workspace
+
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-initial.html b/third_party/WebKit/LayoutTests/inspector/modules-load-initial.html
new file mode 100644
index 0000000..318df48
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-initial.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script>
+function test()
+{
+    InspectorTest.dumpLoadedModules();
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<p>This test validates initial set of loaded modules.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-network-expected.txt b/third_party/WebKit/LayoutTests/inspector/modules-load-network-expected.txt
new file mode 100644
index 0000000..57894491
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-network-expected.txt
@@ -0,0 +1,16 @@
+This test validates set of loaded modules for Network panel.
+
+Loaded modules:
+    cm
+    cookie_table
+    data_grid
+    diff
+    formatter
+    network
+    network_priorities
+    object_ui
+    perf_ui
+    source_frame
+    text_editor
+    workspace_diff
+
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-network.html b/third_party/WebKit/LayoutTests/inspector/modules-load-network.html
new file mode 100644
index 0000000..e8d7d95
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-network.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script>
+async function test()
+{
+    var initialModules = InspectorTest.loadedModules();
+    await UI.inspectorView.panel("network");
+    InspectorTest.dumpLoadedModules(initialModules);
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<p>This test validates set of loaded modules for Network panel.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-source-expected.txt b/third_party/WebKit/LayoutTests/inspector/modules-load-source-expected.txt
new file mode 100644
index 0000000..8db2d41c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-source-expected.txt
@@ -0,0 +1,19 @@
+This test validates set of loaded modules for Sources panel.
+
+Loaded modules:
+    cm
+    color_picker
+    diff
+    event_listeners
+    formatter
+    inline_editor
+    object_ui
+    quick_open
+    snippets
+    source_frame
+    sources
+    text_editor
+    workspace_diff
+Now with source code opened
+Loaded modules:
+
diff --git a/third_party/WebKit/LayoutTests/inspector/modules-load-source.html b/third_party/WebKit/LayoutTests/inspector/modules-load-source.html
new file mode 100644
index 0000000..d78045a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/modules-load-source.html
@@ -0,0 +1,30 @@
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script>
+async function test()
+{
+    var initialModules = InspectorTest.loadedModules();
+    await UI.inspectorView.panel("sources");
+    var sourcesModules = InspectorTest.dumpLoadedModules(initialModules);
+
+    var resource;
+    InspectorTest.resourceTreeModel.forAllResources(function(r) {
+        if (r.url.indexOf("inspector-test.js") !== -1) {
+            resource = r;
+            return true;
+        }
+    });
+    InspectorTest.addResult("Now with source code opened");
+    var uiLocation = Workspace.workspace.uiSourceCodeForURL(resource.url).uiLocation(2, 1);
+    Common.Revealer.reveal(uiLocation);
+    InspectorTest.dumpLoadedModules(sourcesModules);
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+
+<body onload="runTest()">
+<p>This test validates set of loaded modules for Sources panel.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/callback-alive-after-gc.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/callback-alive-after-gc.html
index bfe2ab1ef..3d82cec 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/callback-alive-after-gc.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/callback-alive-after-gc.html
@@ -2,8 +2,9 @@
 <title>Test that setting MediaSession callbacks are alive after garbage-collection</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
 <script src="../../../resources/gc.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -11,15 +12,13 @@
 var mock;
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    mock = m;
-    mock.setClientCallback(_ => {
-      gc();
-      setTimeout(_ => {
-        mock.getClient().didReceiveAction(MediaSessionAction.PLAY);
-      });
+  let mock = mediaSessionServiceMock;
+  mock.setClientCallback(_ => {
+    gc();
+    setTimeout(_ => {
+      mock.getClient().didReceiveAction(MediaSessionAction.PLAY);
     });
-    window.navigator.mediaSession.setActionHandler("play", _ => { t.done(); });
   });
+  window.navigator.mediaSession.setActionHandler("play", _ => { t.done(); });
 });
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/file-image-removed.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/file-image-removed.html
index 78c01a3..2c79ecc 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/file-image-removed.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/file-image-removed.html
@@ -2,25 +2,25 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    var metadata = new MediaMetadata({
-      artwork: [
-        { src: "file:///foo/bar.jpg", type: "image/jpeg"}
-      ]});
-    var expectedMetadata = new MediaMetadata({});
+  let m = mediaSessionServiceMock;
+  var metadata = new MediaMetadata({
+    artwork: [
+      { src: "file:///foo/bar.jpg", type: "image/jpeg"}
+    ]});
+  var expectedMetadata = new MediaMetadata({});
 
-    m.setMetadataCallback(t.step_func(function(receivedMetadata) {
-      assert_metadata_equals(expectedMetadata, receivedMetadata);
-      t.done();
-    }));
-    window.navigator.mediaSession.metadata = metadata;
-  });
+  m.setMetadataCallback(t.step_func(function(receivedMetadata) {
+    assert_metadata_equals(expectedMetadata, receivedMetadata);
+    t.done();
+  }));
+  window.navigator.mediaSession.metadata = metadata;
 }, "test that null MediaMetadata is correctly propagated");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-action-reaches-client.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-action-reaches-client.html
index ab4a42f..6c633bd 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-action-reaches-client.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-action-reaches-client.html
@@ -2,7 +2,8 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -52,12 +53,10 @@
 // Use async_test to do asynchronous setup since setup() only works for
 // synchronous setup.
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    mock = m;
-    mock.setClientCallback(t.step_func(runTests.bind(null, t)));
-    // Touch window.navigator.mediaSession to start the service.
-    window.navigator.mediaSession.metadata = null;
-  });
+  mock = mediaSessionServiceMock;
+  mock.setClientCallback(t.step_func(runTests.bind(null, t)));
+  // Touch window.navigator.mediaSession to start the service.
+  window.navigator.mediaSession.metadata = null;
 }, "test that the mock service is setup");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-set-handler-notifies-service.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-set-handler-notifies-service.html
index ed142a3..8d7c6ca 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-set-handler-notifies-service.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/media-control-set-handler-notifies-service.html
@@ -2,7 +2,8 @@
 <title>Test that setting MediaSession event handler should notify the service</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -39,56 +40,55 @@
 }
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    m.setEnableDisableActionCallback(t.step_func(function(action, isEnabled) {
-      var expectedAction = getExpectations()[nextExpectation][0];
-      var expectedIsEnabled = getExpectations()[nextExpectation][1];
-      assert_equals(expectedAction, action);
-      assert_equals(expectedIsEnabled, isEnabled);
-      if (++nextExpectation >= getExpectations().length)
-        t.done();
-    }));
+  let m = mediaSessionServiceMock;
+  m.setEnableDisableActionCallback(t.step_func(function(action, isEnabled) {
+    var expectedAction = getExpectations()[nextExpectation][0];
+    var expectedIsEnabled = getExpectations()[nextExpectation][1];
+    assert_equals(expectedAction, action);
+    assert_equals(expectedIsEnabled, isEnabled);
+    if (++nextExpectation >= getExpectations().length)
+      t.done();
+  }));
 
-    // Setting handlers should notify the service.
-    window.navigator.mediaSession.setActionHandler("play", _ => {});
-    window.navigator.mediaSession.setActionHandler("pause", _ => {});
-    window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
+  // Setting handlers should notify the service.
+  window.navigator.mediaSession.setActionHandler("play", _ => {});
+  window.navigator.mediaSession.setActionHandler("pause", _ => {});
+  window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
 
-    // Setting handlers again should not notify the service.
-    window.navigator.mediaSession.setActionHandler("play", _ => {});
-    window.navigator.mediaSession.setActionHandler("pause", _ => {});
-    window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
+  // Setting handlers again should not notify the service.
+  window.navigator.mediaSession.setActionHandler("play", _ => {});
+  window.navigator.mediaSession.setActionHandler("pause", _ => {});
+  window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
 
-    // Unsetting handlers should notify the service.
-    window.navigator.mediaSession.setActionHandler("play", null);
-    window.navigator.mediaSession.setActionHandler("pause", null);
-    window.navigator.mediaSession.setActionHandler("previoustrack", null);
-    window.navigator.mediaSession.setActionHandler("nexttrack", null);
-    window.navigator.mediaSession.setActionHandler("seekbackward", null);
-    window.navigator.mediaSession.setActionHandler("seekforward", null);
+  // Unsetting handlers should notify the service.
+  window.navigator.mediaSession.setActionHandler("play", null);
+  window.navigator.mediaSession.setActionHandler("pause", null);
+  window.navigator.mediaSession.setActionHandler("previoustrack", null);
+  window.navigator.mediaSession.setActionHandler("nexttrack", null);
+  window.navigator.mediaSession.setActionHandler("seekbackward", null);
+  window.navigator.mediaSession.setActionHandler("seekforward", null);
 
-    // Unsetting handlers should not notify the service.
-    window.navigator.mediaSession.setActionHandler("play", null);
-    window.navigator.mediaSession.setActionHandler("pause", null);
-    window.navigator.mediaSession.setActionHandler("previoustrack", null);
-    window.navigator.mediaSession.setActionHandler("nexttrack", null);
-    window.navigator.mediaSession.setActionHandler("seekbackward", null);
-    window.navigator.mediaSession.setActionHandler("seekforward", null);
+  // Unsetting handlers should not notify the service.
+  window.navigator.mediaSession.setActionHandler("play", null);
+  window.navigator.mediaSession.setActionHandler("pause", null);
+  window.navigator.mediaSession.setActionHandler("previoustrack", null);
+  window.navigator.mediaSession.setActionHandler("nexttrack", null);
+  window.navigator.mediaSession.setActionHandler("seekbackward", null);
+  window.navigator.mediaSession.setActionHandler("seekforward", null);
 
-    // Setting handlers again should notify the service.
-    window.navigator.mediaSession.setActionHandler("play", _ => {});
-    window.navigator.mediaSession.setActionHandler("pause", _ => {});
-    window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
-    window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
-  });
+  // Setting handlers again should notify the service.
+  window.navigator.mediaSession.setActionHandler("play", _ => {});
+  window.navigator.mediaSession.setActionHandler("pause", _ => {});
+  window.navigator.mediaSession.setActionHandler("previoustrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("nexttrack", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekbackward", _ => {});
+  window.navigator.mediaSession.setActionHandler("seekforward", _ => {});
 }, "test that setting event handler notifies the mojo service");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-async.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-async.html
index 5350c48..6bbd4cf 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-async.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-async.html
@@ -2,7 +2,8 @@
 <title>MediaMetadata Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -38,33 +39,32 @@
   ];
   var resultId = 0;
 
-  mediaSessionServiceMock.then(m => {
-    m.setMetadataCallback(t.step_func(receivedMetadata => {
-      assert_metadata_equals(receivedMetadata, results[resultId]);
-      ++resultId;
+  let m = mediaSessionServiceMock;
+  m.setMetadataCallback(t.step_func(receivedMetadata => {
+    assert_metadata_equals(receivedMetadata, results[resultId]);
+    ++resultId;
 
-      if (results.length == resultId)
-        t.done();
-    }));
+    if (results.length == resultId)
+      t.done();
+  }));
 
-    // Setting the metadata property will update the mojo service.
-    window.navigator.mediaSession.metadata = new MediaMetadata({});
+  // Setting the metadata property will update the mojo service.
+  window.navigator.mediaSession.metadata = new MediaMetadata({});
 
-    // All the next lines will produce only one call.
-    window.navigator.mediaSession.metadata.title = 'new title';
-    window.navigator.mediaSession.metadata.album = 'new album';
-    window.navigator.mediaSession.metadata.artist = 'new artist';
-    window.navigator.mediaSession.metadata.artwork = [
-      { src: 'http://example.com/', sizes: '40x40', type: 'image/png' }
-    ];
+  // All the next lines will produce only one call.
+  window.navigator.mediaSession.metadata.title = 'new title';
+  window.navigator.mediaSession.metadata.album = 'new album';
+  window.navigator.mediaSession.metadata.artist = 'new artist';
+  window.navigator.mediaSession.metadata.artwork = [
+    { src: 'http://example.com/', sizes: '40x40', type: 'image/png' }
+  ];
 
-    // This two last changes are made asynchronously and will go in different
-    // mojo calls.
+  // This two last changes are made asynchronously and will go in different
+  // mojo calls.
+  setTimeout(_ => {
+    window.navigator.mediaSession.metadata.title = 'first timeout';
     setTimeout(_ => {
-      window.navigator.mediaSession.metadata.title = 'first timeout';
-      setTimeout(_ => {
-        window.navigator.mediaSession.metadata.title = 'second timeout';
-      });
+      window.navigator.mediaSession.metadata.title = 'second timeout';
     });
   });
 }, "test that MediaMetadata is correctly propagated twice");
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated-twice.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated-twice.html
index 2715ed04d..83481dc 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated-twice.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated-twice.html
@@ -2,32 +2,32 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    var dontCareMetadata = new MediaMetadata({});
+  let m = mediaSessionServiceMock;
+  var dontCareMetadata = new MediaMetadata({});
 
-    m.setMetadataCallback(t.step_func(function() {
-      var metadata = new MediaMetadata({
-        title: "title2",
-        artist: "artist2",
-        album: "album2",
-        artwork: [
-          { src: "http://foo.com/bar.jpg", type: "image/jpeg", sizes: "256x256"}
-        ]});
+  m.setMetadataCallback(t.step_func(function() {
+    var metadata = new MediaMetadata({
+      title: "title2",
+      artist: "artist2",
+      album: "album2",
+      artwork: [
+        { src: "http://foo.com/bar.jpg", type: "image/jpeg", sizes: "256x256"}
+      ]});
 
-      m.setMetadataCallback(t.step_func(function(receivedMetadata) {
-        assert_metadata_equals(metadata, receivedMetadata);
-        t.done();
-      }));
-      window.navigator.mediaSession.metadata = metadata;
+    m.setMetadataCallback(t.step_func(function(receivedMetadata) {
+      assert_metadata_equals(metadata, receivedMetadata);
+      t.done();
     }));
-    window.navigator.mediaSession.metadata = dontCareMetadata;
-  });
+    window.navigator.mediaSession.metadata = metadata;
+  }));
+  window.navigator.mediaSession.metadata = dontCareMetadata;
 }, "test that MediaMetadata is correctly propagated twice");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated.html
index 28d594b3..b8c418b 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-propagated.html
@@ -2,27 +2,27 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    var metadata = new MediaMetadata({
-      title: "title1",
-      artist: "artist1",
-      album: "album1",
-      artwork: [
-        { src: "http://foo.com/bar.png", type: "image/png", sizes: "128x128" }
-      ]});
+  let m = mediaSessionServiceMock;
+  var metadata = new MediaMetadata({
+    title: "title1",
+    artist: "artist1",
+    album: "album1",
+    artwork: [
+      { src: "http://foo.com/bar.png", type: "image/png", sizes: "128x128" }
+    ]});
 
-    m.setMetadataCallback(t.step_func(function(receivedMetadata) {
-      assert_metadata_equals(metadata, receivedMetadata);
-      t.done();
-    }));
-    window.navigator.mediaSession.metadata = metadata;
-  });
+  m.setMetadataCallback(t.step_func(function(receivedMetadata) {
+    assert_metadata_equals(metadata, receivedMetadata);
+    t.done();
+  }));
+  window.navigator.mediaSession.metadata = metadata;
 }, "test that MediaMetadata is correctly propagated");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-session-link.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-session-link.html
index 2741233..2636e06 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-session-link.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/metadata-session-link.html
@@ -2,7 +2,8 @@
 <title>MediaMetadata / MediaSession link Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -23,38 +24,37 @@
   ];
   var resultId = 0;
 
-  mediaSessionServiceMock.then(m => {
-    m.setMetadataCallback(t.step_func(receivedMetadata => {
-      assert_metadata_equals(receivedMetadata, results[resultId]);
-      ++resultId;
+  let m = mediaSessionServiceMock;
+  m.setMetadataCallback(t.step_func(receivedMetadata => {
+    assert_metadata_equals(receivedMetadata, results[resultId]);
+    ++resultId;
 
-      if (results.length == resultId)
-        t.done();
-    }));
+    if (results.length == resultId)
+      t.done();
+  }));
 
-    // Setting the metadata property will update the mojo service.
-    var currentMetadata = new MediaMetadata({});
-    window.navigator.mediaSession.metadata = currentMetadata;
+  // Setting the metadata property will update the mojo service.
+  var currentMetadata = new MediaMetadata({});
+  window.navigator.mediaSession.metadata = currentMetadata;
 
-    // `currentMetadata` is still associated to MediaSession.
-    currentMetadata.title = 'new title';
+  // `currentMetadata` is still associated to MediaSession.
+  currentMetadata.title = 'new title';
 
-    // De-associate them.
-    setTimeout(_ => {
-      // This change will trigger an asynchronous request for an update. It is
-      // Followed by another change that will prevent the former to work.
-      currentMetadata.title = 'should not be received';
+  // De-associate them.
+  setTimeout(_ => {
+    // This change will trigger an asynchronous request for an update. It is
+    // Followed by another change that will prevent the former to work.
+    currentMetadata.title = 'should not be received';
 
-      var otherMetadata = new MediaMetadata({ title: 'other' });
-      window.navigator.mediaSession.metadata = otherMetadata;
+    var otherMetadata = new MediaMetadata({ title: 'other' });
+    window.navigator.mediaSession.metadata = otherMetadata;
 
-      // `currentMetadata` is no longer linked with the session so changes
-      // should have no effect.
-      currentMetadata.title = 'another attempt';
+    // `currentMetadata` is no longer linked with the session so changes
+    // should have no effect.
+    currentMetadata.title = 'another attempt';
 
-      // This one will be received.
-      otherMetadata.title = 'the right change';
-    });
+    // This one will be received.
+    otherMetadata.title = 'the right change';
   });
 }, "test that MediaMetadata is correctly propagated twice");
 
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/playback-state-propagated.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/playback-state-propagated.html
index 5599679..43e885c4 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/playback-state-propagated.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/playback-state-propagated.html
@@ -2,7 +2,8 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
@@ -25,15 +26,14 @@
 }
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    m.setPlaybackStateCallback(t.step_func(function(state) {
-      assert_equals(state, getExpectations()[nextExpectation++]);
-      if (nextExpectation == getExpectations().length)
-        t.done();
-    }));
-    for (let state of inputStates)
-      window.navigator.mediaSession.playbackState = state;
-  });
+  let m = mediaSessionServiceMock;
+  m.setPlaybackStateCallback(t.step_func(function(state) {
+    assert_equals(state, getExpectations()[nextExpectation++]);
+    if (nextExpectation == getExpectations().length)
+      t.done();
+  }));
+  for (let state of inputStates)
+    window.navigator.mediaSession.playbackState = state;
 }, "test that MediaSession.playbackState is correctly propagated");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js b/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
index 963e40e0..f257db6 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/resources/mediasessionservice-mock.js
@@ -4,9 +4,6 @@
 
 "use strict";
 
-var MediaSessionAction;
-var MediaSessionPlaybackState;
-
 function mojoString16ToJS(mojoString16) {
   return String.fromCharCode.apply(null, mojoString16.data);
 }
@@ -39,73 +36,67 @@
   return new MediaMetadata({title: title, artist: artist, album: album, artwork: artwork});
 }
 
-let mediaSessionServiceMock = loadMojoModules(
-    'mediaSessionServiceMock',
-    ['third_party/WebKit/public/platform/modules/mediasession/media_session.mojom',
-     'mojo/public/js/bindings',
-    ]).then(mojo => {
-      let [mediaSessionService, bindings] = mojo.modules;
+var MediaSessionAction = blink.mojom.MediaSessionAction;
+var MediaSessionPlaybackState = blink.mojom.MediaSessionPlaybackState;
 
-      MediaSessionAction = mediaSessionService.MediaSessionAction;
-      MediaSessionPlaybackState = mediaSessionService.MediaSessionPlaybackState;
+class MediaSessionServiceMock {
+  constructor() {
+    this.pendingResponse_ = null;
+    this.bindingSet_ = new mojo.BindingSet(
+        blink.mojom.MediaSessionService);
 
-      class MediaSessionServiceMock {
-        constructor(interfaceProvider) {
-          interfaceProvider.addInterfaceOverrideForTesting(
-              mediaSessionService.MediaSessionService.name,
-              handle => this.bindingSet_.addBinding(this, handle));
-          this.interfaceProvider_ = interfaceProvider;
-          this.pendingResponse_ = null;
-          this.bindingSet_ = new bindings.BindingSet(
-              mediaSessionService.MediaSessionService);
-        }
+    this.interceptor_ =
+        new MojoInterfaceInterceptor(blink.mojom.MediaSessionService.name);
+    this.interceptor_.oninterfacerequest =
+        e => this.bindingSet_.addBinding(this, e.handle);
+    this.interceptor_.start();
+  }
 
-        setMetadata(metadata) {
-          if (!!this.metadataCallback_)
-            this.metadataCallback_(mojoMetadataToJS(metadata));
-        }
+  setMetadata(metadata) {
+    if (!!this.metadataCallback_)
+      this.metadataCallback_(mojoMetadataToJS(metadata));
+  }
 
-        setMetadataCallback(callback) {
-          this.metadataCallback_ = callback;
-        }
+  setMetadataCallback(callback) {
+    this.metadataCallback_ = callback;
+  }
 
-        setPlaybackState(state) {
-          if (!!this.setPlaybackStateCallback_)
-            this.setPlaybackStateCallback_(state);
-        }
+  setPlaybackState(state) {
+    if (!!this.setPlaybackStateCallback_)
+      this.setPlaybackStateCallback_(state);
+  }
 
-        setPlaybackStateCallback(callback) {
-          this.setPlaybackStateCallback_ = callback;
-        }
+  setPlaybackStateCallback(callback) {
+    this.setPlaybackStateCallback_ = callback;
+  }
 
-        enableAction(action) {
-          if (!!this.enableDisableActionCallback_)
-            this.enableDisableActionCallback_(action, true);
-        }
+  enableAction(action) {
+    if (!!this.enableDisableActionCallback_)
+      this.enableDisableActionCallback_(action, true);
+  }
 
-        disableAction(action) {
-          if (!!this.enableDisableActionCallback_)
-            this.enableDisableActionCallback_(action, false);
-        }
+  disableAction(action) {
+    if (!!this.enableDisableActionCallback_)
+      this.enableDisableActionCallback_(action, false);
+  }
 
-        setEnableDisableActionCallback(callback) {
-          this.enableDisableActionCallback_ = callback;
-        }
+  setEnableDisableActionCallback(callback) {
+    this.enableDisableActionCallback_ = callback;
+  }
 
-        setClient(client) {
-          this.client_ = client;
-          if (!!this.clientCallback_)
-            this.clientCallback_();
-        }
+  setClient(client) {
+    this.client_ = client;
+    if (!!this.clientCallback_)
+      this.clientCallback_();
+  }
 
-        setClientCallback(callback) {
-          this.clientCallback_ = callback;
-        }
+  setClientCallback(callback) {
+    this.clientCallback_ = callback;
+  }
 
-        getClient() {
-          return this.client_;
-        }
-      }
+  getClient() {
+    return this.client_;
+  }
+}
 
-      return new MediaSessionServiceMock(mojo.frameInterfaces);
-    });
+let mediaSessionServiceMock = new MediaSessionServiceMock();
diff --git a/third_party/WebKit/LayoutTests/media/mediasession/mojo/set-null-metadata.html b/third_party/WebKit/LayoutTests/media/mediasession/mojo/set-null-metadata.html
index 3039c6a..f4925ae 100644
--- a/third_party/WebKit/LayoutTests/media/mediasession/mojo/set-null-metadata.html
+++ b/third_party/WebKit/LayoutTests/media/mediasession/mojo/set-null-metadata.html
@@ -2,19 +2,19 @@
 <title>MediaSession Mojo Test</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/mediasession/media_session.mojom.js"></script>
 <script src="resources/mediasessionservice-mock.js"></script>
 <script src="resources/utils.js"></script>
 <script>
 
 async_test(function(t) {
-  mediaSessionServiceMock.then(m => {
-    m.setMetadataCallback(t.step_func(function(receivedMetadata) {
-      assert_equals(receivedMetadata, null);
-      t.done();
-    }));
-    window.navigator.mediaSession.metadata = null;
-  });
+  let m = mediaSessionServiceMock;
+  m.setMetadataCallback(t.step_func(function(receivedMetadata) {
+    assert_equals(receivedMetadata, null);
+    t.done();
+  }));
+  window.navigator.mediaSession.metadata = null;
 }, "test that null MediaMetadata is correctly propagated");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-zoom-coords-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-zoom-coords-expected.txt
index e5e4afc..cf06610 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-zoom-coords-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-zoom-coords-expected.txt
@@ -81,8 +81,8 @@
 PASS text2.top is 132.66
 FAIL text2.width should be 47.98. Was 47.85938262939453.
 FAIL text2.height should be 6.02. Was 5.921872138977051.
-FAIL text2.right should be 222.98. Was 222.859375.
-FAIL text2.bottom should be 138.7. Was 138.59375.
+FAIL text2.right should be 222.98. Was 222.85938262939453.
+FAIL text2.bottom should be 138.7. Was 138.59374713897705.
 
 PASS svg3.left is 900.00
 PASS svg3.top is 500.00
@@ -106,7 +106,7 @@
 PASS text3.top is 565.33
 FAIL text3.width should be 95.97. Was 98.3750228881836.
 PASS text3.height is 12.31
-FAIL text3.right should be 1195.97. Was 1198.375.
+FAIL text3.right should be 1195.97. Was 1198.3750228881836.
 PASS text3.bottom is 577.64
 
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS
new file mode 100644
index 0000000..95fbf480
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+# Web-exposed API changes may require approval from blink API OWNERS.
+# See http://www.chromium.org/blink#new-features for details.
+file://third_party/WebKit/API_OWNERS
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
index 4757310..715eb4fc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -600,21 +600,6 @@
     method replaceWith
     method substringData
     setter data
-interface ClientRect
-    attribute @@toStringTag
-    getter bottom
-    getter height
-    getter left
-    getter right
-    getter top
-    getter width
-    method constructor
-interface ClientRectList
-    attribute @@toStringTag
-    getter length
-    method @@iterator
-    method constructor
-    method item
 interface Clipboard : EventTarget
     attribute @@toStringTag
     method constructor
@@ -1357,7 +1342,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1432,7 +1416,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -1975,6 +1958,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2066,6 +2050,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -4789,6 +4774,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -4870,6 +4856,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-zoom-coords-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-zoom-coords-expected.txt
index 8d7ebc5..0fe5fbf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-zoom-coords-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-zoom-coords-expected.txt
@@ -81,8 +81,8 @@
 PASS text2.top is 132.66
 FAIL text2.width should be 47.98. Was 47.421878814697266.
 FAIL text2.height should be 6.02. Was 5.921872138977051.
-FAIL text2.right should be 222.98. Was 222.421875.
-FAIL text2.bottom should be 138.7. Was 138.59375.
+FAIL text2.right should be 222.98. Was 222.42187881469727.
+FAIL text2.bottom should be 138.7. Was 138.59374713897705.
 
 PASS svg3.left is 900.00
 PASS svg3.top is 500.00
@@ -106,7 +106,7 @@
 PASS text3.top is 565.33
 FAIL text3.width should be 95.97. Was 98.3750228881836.
 PASS text3.height is 12.31
-FAIL text3.right should be 1195.97. Was 1198.375.
+FAIL text3.right should be 1195.97. Was 1198.3750228881836.
 PASS text3.bottom is 577.64
 
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index 65eb1cda..1a42282 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -529,21 +529,6 @@
     method replaceWith
     method substringData
     setter data
-interface ClientRect
-    attribute @@toStringTag
-    getter bottom
-    getter height
-    getter left
-    getter right
-    getter top
-    getter width
-    method constructor
-interface ClientRectList
-    attribute @@toStringTag
-    getter length
-    method @@iterator
-    method constructor
-    method item
 interface Clipboard : EventTarget
     attribute @@toStringTag
     method constructor
@@ -1286,7 +1271,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1361,7 +1345,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -1904,6 +1887,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -1995,6 +1979,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -4718,6 +4703,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -4799,6 +4785,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/LayoutTests/security/block-test-expected.txt b/third_party/WebKit/LayoutTests/security/block-test-expected.txt
index 233c9b8..8ab4eae0 100644
--- a/third_party/WebKit/LayoutTests/security/block-test-expected.txt
+++ b/third_party/WebKit/LayoutTests/security/block-test-expected.txt
@@ -131,7 +131,7 @@
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:65536/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:4294967295/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for http://255.255.255.255:4294967296/test.jpg
-CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
+CONSOLE WARNING: Subresource requests using legacy protocols (like `ftp:`) are blocked. Please deliver web-accessible resources over modern protocols like HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for details.
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255:21/test.jpg
 CONSOLE MESSAGE: line 32: PASS: error event fired for ftp://255.255.255.255:22/test.jpg
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 6fce2fc..44e6215 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -1010,21 +1010,6 @@
     method replaceWith
     method substringData
     setter data
-interface ClientRect
-    attribute @@toStringTag
-    getter bottom
-    getter height
-    getter left
-    getter right
-    getter top
-    getter width
-    method constructor
-interface ClientRectList
-    attribute @@toStringTag
-    getter length
-    method @@iterator
-    method constructor
-    method item
 interface Clipboard : EventTarget
     attribute @@toStringTag
     method constructor
@@ -1815,7 +1800,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1895,7 +1879,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -2466,6 +2449,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2559,6 +2543,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -5567,6 +5552,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -5648,6 +5634,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index befa5470..d530b63 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1010,21 +1010,6 @@
     method replaceWith
     method substringData
     setter data
-interface ClientRect
-    attribute @@toStringTag
-    getter bottom
-    getter height
-    getter left
-    getter right
-    getter top
-    getter width
-    method constructor
-interface ClientRectList
-    attribute @@toStringTag
-    getter length
-    method @@iterator
-    method constructor
-    method item
 interface Clipboard : EventTarget
     attribute @@toStringTag
     method constructor
@@ -1815,7 +1800,6 @@
     getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
-    getter onwheel
     getter outerHTML
     getter prefix
     getter previousElementSibling
@@ -1895,7 +1879,6 @@
     setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
-    setter onwheel
     setter outerHTML
     setter scrollLeft
     setter scrollTop
@@ -2466,6 +2449,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter outerText
     getter spellcheck
     getter style
@@ -2559,6 +2543,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter outerText
     setter spellcheck
     setter style
@@ -5574,6 +5559,7 @@
     getter ontouchstart
     getter onvolumechange
     getter onwaiting
+    getter onwheel
     getter ownerSVGElement
     getter style
     getter tabIndex
@@ -5655,6 +5641,7 @@
     setter ontouchstart
     setter onvolumechange
     setter onwaiting
+    setter onwheel
     setter style
     setter tabIndex
 interface SVGEllipseElement : SVGGeometryElement
diff --git a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
index f094f00..ce5971a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
@@ -121,6 +121,9 @@
     case v8::Isolate::kPromiseConstructorReturnedUndefined:
       blink_feature = WebFeature::kV8PromiseConstructorReturnedUndefined;
       break;
+    case v8::Isolate::kConstructorNonUndefinedPrimitiveReturn:
+      blink_feature = WebFeature::kV8ConstructorNonUndefinedPrimitiveReturn;
+      break;
     default:
       // This can happen if V8 has added counters that this version of Blink
       // does not know about. It's harmless.
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index f6cc9e7..c56edc2 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -91,8 +91,6 @@
                                  "dom/Attr.idl",
                                  "dom/CDATASection.idl",
                                  "dom/CharacterData.idl",
-                                 "dom/ClientRect.idl",
-                                 "dom/ClientRectList.idl",
                                  "dom/Comment.idl",
                                  "dom/DOMException.idl",
                                  "dom/DOMImplementation.idl",
@@ -189,6 +187,7 @@
                                  "geometry/DOMPointReadOnly.idl",
                                  "geometry/DOMQuad.idl",
                                  "geometry/DOMRect.idl",
+                                 "geometry/DOMRectList.idl",
                                  "geometry/DOMRectReadOnly.idl",
                                  "html/FormData.idl",
                                  "html/HTMLAllCollection.idl",
diff --git a/third_party/WebKit/Source/core/dom/BUILD.gn b/third_party/WebKit/Source/core/dom/BUILD.gn
index 850f480..cc2f9b1 100644
--- a/third_party/WebKit/Source/core/dom/BUILD.gn
+++ b/third_party/WebKit/Source/core/dom/BUILD.gn
@@ -42,10 +42,6 @@
     "ClassicPendingScript.h",
     "ClassicScript.cpp",
     "ClassicScript.h",
-    "ClientRect.cpp",
-    "ClientRect.h",
-    "ClientRectList.cpp",
-    "ClientRectList.h",
     "CollectionIndexCache.h",
     "Comment.cpp",
     "Comment.h",
diff --git a/third_party/WebKit/Source/core/dom/ClientRect.cpp b/third_party/WebKit/Source/core/dom/ClientRect.cpp
deleted file mode 100644
index 0fac4353..0000000
--- a/third_party/WebKit/Source/core/dom/ClientRect.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- *
- */
-
-#include "core/dom/ClientRect.h"
-
-namespace blink {
-
-ClientRect::ClientRect() {}
-
-ClientRect::ClientRect(const IntRect& rect) : rect_(rect) {}
-
-ClientRect::ClientRect(const FloatRect& rect) : rect_(rect) {}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ClientRect.h b/third_party/WebKit/Source/core/dom/ClientRect.h
deleted file mode 100644
index e5a8f50..0000000
--- a/third_party/WebKit/Source/core/dom/ClientRect.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ClientRect_h
-#define ClientRect_h
-
-#include "core/CoreExport.h"
-#include "platform/bindings/ScriptWrappable.h"
-#include "platform/geometry/FloatRect.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class IntRect;
-
-class CORE_EXPORT ClientRect final : public GarbageCollected<ClientRect>,
-                                     public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static ClientRect* Create() { return new ClientRect; }
-  static ClientRect* Create(const IntRect& rect) {
-    return new ClientRect(rect);
-  }
-  static ClientRect* Create(const FloatRect& rect) {
-    return new ClientRect(rect);
-  }
-
-  float top() const { return rect_.Y(); }
-  float right() const { return rect_.MaxX(); }
-  float bottom() const { return rect_.MaxY(); }
-  float left() const { return rect_.X(); }
-  float width() const { return rect_.Width(); }
-  float height() const { return rect_.Height(); }
-
-  DEFINE_INLINE_TRACE() {}
-
- private:
-  ClientRect();
-  explicit ClientRect(const IntRect&);
-  explicit ClientRect(const FloatRect&);
-
-  FloatRect rect_;
-};
-
-}  // namespace blink
-
-#endif  // ClientRect_h
diff --git a/third_party/WebKit/Source/core/dom/ClientRect.idl b/third_party/WebKit/Source/core/dom/ClientRect.idl
deleted file mode 100644
index 2e9a66e..0000000
--- a/third_party/WebKit/Source/core/dom/ClientRect.idl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- *
- */
-
-// An old version of CSSOM View Module defines the ClientRect interface:
-// https://www.w3.org/TR/2011/WD-cssom-view-20110804/#the-clientrect-interface
-
-// It has since been replaced by DOMRect in CSSOM View Module and
-// Geometry Interfaces Module:
-// https://drafts.csswg.org/cssom-view/#extension-to-the-element-interface
-// https://drafts.fxtf.org/geometry/#DOMRect
-
-interface ClientRect {
-    readonly attribute float top;
-    readonly attribute float right;
-    readonly attribute float bottom;
-    readonly attribute float left;
-    readonly attribute float width;
-    readonly attribute float height;
-};
diff --git a/third_party/WebKit/Source/core/dom/ClientRectList.idl b/third_party/WebKit/Source/core/dom/ClientRectList.idl
deleted file mode 100644
index 31767a6c..0000000
--- a/third_party/WebKit/Source/core/dom/ClientRectList.idl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- *
- */
-
-// An old version of CSSOM View Module defines the ClientRectList interface:
-// https://www.w3.org/TR/2011/WD-cssom-view-20110804/#the-clientrectlist-interface
-
-// It has since been replace by DOMRectList in CSSOM View Module and
-// Geometry Interfaces Module:
-// https://dev.w3.org/csswg/cssom-view/#extension-to-the-element-interface
-// https://drafts.fxtf.org/geometry/#DOMRectList
-
-// CSSOM View Module also says: "The DOMRectList interface is at-risk.
-// The authors of this specification await feedback from implementers
-// if the item() function of DOMRectList is currently in use on legacy
-// interfaces. If there is no/not enough content to justify
-// DOMRectList, legacy interfaces must use sequences instead and
-// DOMRectList will be removed from this specification."
-
-interface ClientRectList {
-    readonly attribute unsigned long length;
-    [MeasureAs=ClientRectListItem] ClientRect item(unsigned long index);
-    getter ClientRect (unsigned long index);
-};
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 8295d60..5e859cb1 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -66,7 +66,6 @@
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/Attr.h"
 #include "core/dom/CDATASection.h"
-#include "core/dom/ClientRect.h"
 #include "core/dom/Comment.h"
 #include "core/dom/ContextFeatures.h"
 #include "core/dom/DOMImplementation.h"
@@ -1801,9 +1800,6 @@
   DCHECK(ShouldScheduleLayoutTreeUpdate());
   DCHECK(NeedsLayoutTreeUpdate());
 
-  // TODO(szager): Remove this CHECK after checking crash reports.
-  CHECK(lifecycle_.GetState() != DocumentLifecycle::kInPerformLayout);
-
   if (!View()->CanThrottleRendering())
     GetPage()->Animator().ScheduleVisualUpdate(GetFrame());
   lifecycle_.EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 03947a0c..bb06568 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -302,7 +302,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(securitypolicyviolation);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectionchange);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   bool ShouldMergeWithLegacyDescription(ViewportDescription::Type) const;
   bool ShouldOverrideLegacyDescription(ViewportDescription::Type) const;
diff --git a/third_party/WebKit/Source/core/dom/Document.idl b/third_party/WebKit/Source/core/dom/Document.idl
index 5b72874..3a74b3e8 100644
--- a/third_party/WebKit/Source/core/dom/Document.idl
+++ b/third_party/WebKit/Source/core/dom/Document.idl
@@ -210,7 +210,6 @@
     [RuntimeEnabled=ExperimentalContentSecurityPolicyFeatures] attribute EventHandler onsecuritypolicyviolation;
     attribute EventHandler onselectionchange;
     attribute EventHandler onselectstart;
-    attribute EventHandler onwheel;
 };
 
 Document implements GlobalEventHandlers;
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index ac67e020..7a10a0f 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -51,8 +51,6 @@
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/Attr.h"
 #include "core/dom/CSSSelectorWatch.h"
-#include "core/dom/ClientRect.h"
-#include "core/dom/ClientRectList.h"
 #include "core/dom/DOMTokenList.h"
 #include "core/dom/DatasetDOMStringMap.h"
 #include "core/dom/ElementDataCache.h"
@@ -98,6 +96,8 @@
 #include "core/frame/UseCounter.h"
 #include "core/frame/VisualViewport.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
+#include "core/geometry/DOMRect.h"
+#include "core/geometry/DOMRectList.h"
 #include "core/html/HTMLCanvasElement.h"
 #include "core/html/HTMLCollection.h"
 #include "core/html/HTMLDocument.h"
@@ -1204,24 +1204,24 @@
     element_layout_object->AbsoluteQuads(quads, kUseTransforms);
 }
 
-ClientRectList* Element::getClientRects() {
+DOMRectList* Element::getClientRects() {
   Vector<FloatQuad> quads;
   ClientQuads(quads);
   if (quads.IsEmpty())
-    return ClientRectList::Create();
+    return DOMRectList::Create();
 
   LayoutObject* element_layout_object = GetLayoutObject();
   DCHECK(element_layout_object);
   GetDocument().AdjustFloatQuadsForScrollAndAbsoluteZoom(
       quads, *element_layout_object);
-  return ClientRectList::Create(quads);
+  return DOMRectList::Create(quads);
 }
 
-ClientRect* Element::getBoundingClientRect() {
+DOMRect* Element::getBoundingClientRect() {
   Vector<FloatQuad> quads;
   ClientQuads(quads);
   if (quads.IsEmpty())
-    return ClientRect::Create();
+    return DOMRect::Create();
 
   FloatRect result = quads[0].BoundingBox();
   for (size_t i = 1; i < quads.size(); ++i)
@@ -1231,7 +1231,7 @@
   DCHECK(element_layout_object);
   GetDocument().AdjustFloatRectForScrollAndAbsoluteZoom(result,
                                                         *element_layout_object);
-  return ClientRect::Create(result);
+  return DOMRect::FromFloatRect(result);
 }
 
 const AtomicString& Element::computedRole() {
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index ba33318..1395bda 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -47,10 +47,10 @@
 class Attr;
 class Attribute;
 class CSSStyleDeclaration;
-class ClientRect;
-class ClientRectList;
 class CompositorMutation;
 class CustomElementDefinition;
+class DOMRect;
+class DOMRectList;
 class DOMStringMap;
 class DOMTokenList;
 class ElementRareData;
@@ -140,7 +140,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   bool hasAttribute(const QualifiedName&) const;
   const AtomicString& getAttribute(const QualifiedName&) const;
@@ -263,8 +262,8 @@
   // used to show popups beside this element.
   IntRect VisibleBoundsInVisualViewport() const;
 
-  ClientRectList* getClientRects();
-  ClientRect* getBoundingClientRect();
+  DOMRectList* getClientRects();
+  DOMRect* getBoundingClientRect();
 
   bool HasNonEmptyLayoutSize() const;
 
diff --git a/third_party/WebKit/Source/core/dom/Element.idl b/third_party/WebKit/Source/core/dom/Element.idl
index fa0e969..67d9dac 100644
--- a/third_party/WebKit/Source/core/dom/Element.idl
+++ b/third_party/WebKit/Source/core/dom/Element.idl
@@ -90,10 +90,8 @@
 
     // CSSOM View Module
     // https://dev.w3.org/csswg/cssom-view/#extension-to-the-element-interface
-    // FIXME: getClientRect() and getBoundingClientRect() should
-    // return DOMRectList and DOMRect respectively.
-    ClientRectList getClientRects();
-    ClientRect getBoundingClientRect();
+    DOMRectList getClientRects();
+    DOMRect getBoundingClientRect();
 
     // TODO(sunyunjia): Add default value for scrollIntoView() once
     // crbug.com/734599 is fixed.
@@ -142,7 +140,6 @@
     attribute EventHandler onpaste;
     attribute EventHandler onsearch;
     attribute EventHandler onselectstart;
-    attribute EventHandler onwheel;
 };
 
 Element implements ParentNode;
diff --git a/third_party/WebKit/Source/core/dom/ElementTest.cpp b/third_party/WebKit/Source/core/dom/ElementTest.cpp
index 7a929364..90386b8 100644
--- a/third_party/WebKit/Source/core/dom/ElementTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ElementTest.cpp
@@ -5,10 +5,10 @@
 #include "core/dom/Element.h"
 
 #include <memory>
-#include "core/dom/ClientRect.h"
 #include "core/dom/Document.h"
 #include "core/editing/EditingTestBase.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLHtmlElement.h"
 #include "core/layout/LayoutBoxModelObject.h"
 #include "core/paint/PaintLayer.h"
@@ -51,7 +51,7 @@
 
   // The sticky element should remain at (0, 25) relative to the viewport due to
   // the constraints.
-  ClientRect* bounding_client_rect = sticky->getBoundingClientRect();
+  DOMRect* bounding_client_rect = sticky->getBoundingClientRect();
   EXPECT_EQ(0, bounding_client_rect->top());
   EXPECT_EQ(25, bounding_client_rect->left());
 
diff --git a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
index 462e3cdc..24b34330 100644
--- a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
+++ b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.h
@@ -108,6 +108,7 @@
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(touchstart);
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(volumechange);
 DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(waiting);
+DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(wheel);
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
index 902056d..6735073b 100644
--- a/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
+++ b/third_party/WebKit/Source/core/dom/GlobalEventHandlers.idl
@@ -94,6 +94,7 @@
     attribute EventHandler ontoggle;
     attribute EventHandler onvolumechange;
     attribute EventHandler onwaiting;
+    attribute EventHandler onwheel;
 
     // auxclick
     // https://wicg.github.io/auxclick/
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
index a337d42..f32a9fb 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.cpp
@@ -18,9 +18,10 @@
     Element* target)
     : time_(time),
       intersection_ratio_(intersection_ratio),
-      bounding_client_rect_(ClientRect::Create(bounding_client_rect)),
-      root_bounds_(root_bounds ? ClientRect::Create(*root_bounds) : nullptr),
-      intersection_rect_(ClientRect::Create(intersection_rect)),
+      bounding_client_rect_(DOMRectReadOnly::FromIntRect(bounding_client_rect)),
+      root_bounds_(root_bounds ? DOMRectReadOnly::FromIntRect(*root_bounds)
+                               : nullptr),
+      intersection_rect_(DOMRectReadOnly::FromIntRect(intersection_rect)),
       target_(target),
       is_intersecting_(is_intersecting)
 
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h
index b567e2f7..7c36931 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.h
@@ -5,8 +5,8 @@
 #ifndef IntersectionObserverEntry_h
 #define IntersectionObserverEntry_h
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/DOMHighResTimeStamp.h"
+#include "core/geometry/DOMRectReadOnly.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/heap/Handle.h"
@@ -31,9 +31,9 @@
 
   double time() const { return time_; }
   double intersectionRatio() const { return intersection_ratio_; }
-  ClientRect* boundingClientRect() const { return bounding_client_rect_; }
-  ClientRect* rootBounds() const { return root_bounds_; }
-  ClientRect* intersectionRect() const { return intersection_rect_; }
+  DOMRectReadOnly* boundingClientRect() const { return bounding_client_rect_; }
+  DOMRectReadOnly* rootBounds() const { return root_bounds_; }
+  DOMRectReadOnly* intersectionRect() const { return intersection_rect_; }
   bool isIntersecting() const { return is_intersecting_; }
   Element* target() const { return target_.Get(); }
 
@@ -42,9 +42,9 @@
  private:
   DOMHighResTimeStamp time_;
   double intersection_ratio_;
-  Member<ClientRect> bounding_client_rect_;
-  Member<ClientRect> root_bounds_;
-  Member<ClientRect> intersection_rect_;
+  Member<DOMRectReadOnly> bounding_client_rect_;
+  Member<DOMRectReadOnly> root_bounds_;
+  Member<DOMRectReadOnly> intersection_rect_;
   Member<Element> target_;
   bool is_intersecting_;
 };
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl
index 7ae9877..fea1aed 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserverEntry.idl
@@ -8,12 +8,10 @@
     RuntimeEnabled=IntersectionObserver
 ] interface IntersectionObserverEntry {
     readonly attribute DOMHighResTimeStamp time;
-    // TODO(szager): |rootBounds| should not be nullable and it,
-    // |boundingClientRect| and |intersectionRect| should all be
-    // DOMRectReadOnly.
-    readonly attribute ClientRect? rootBounds;
-    readonly attribute ClientRect boundingClientRect;
-    readonly attribute ClientRect intersectionRect;
+    // TODO(szager): |rootBounds| should not be nullable.
+    readonly attribute DOMRectReadOnly? rootBounds;
+    readonly attribute DOMRectReadOnly boundingClientRect;
+    readonly attribute DOMRectReadOnly intersectionRect;
     readonly attribute boolean isIntersecting;
     readonly attribute double intersectionRatio;
     readonly attribute Element target;
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp
index dd65859..2b0685b8 100644
--- a/third_party/WebKit/Source/core/dom/Range.cpp
+++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -27,8 +27,6 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/CharacterData.h"
-#include "core/dom/ClientRect.h"
-#include "core/dom/ClientRectList.h"
 #include "core/dom/ContainerNode.h"
 #include "core/dom/DocumentFragment.h"
 #include "core/dom/ExceptionCode.h"
@@ -46,6 +44,8 @@
 #include "core/editing/serializers/Serialization.h"
 #include "core/events/ScopedEventQueue.h"
 #include "core/frame/Settings.h"
+#include "core/geometry/DOMRect.h"
+#include "core/geometry/DOMRectList.h"
 #include "core/html/HTMLBodyElement.h"
 #include "core/html/HTMLElement.h"
 #include "core/layout/LayoutObject.h"
@@ -1596,17 +1596,17 @@
          end.DeepEquivalent().ComputeOffsetInContainerNode(), exception_state);
 }
 
-ClientRectList* Range::getClientRects() const {
+DOMRectList* Range::getClientRects() const {
   owner_document_->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
   Vector<FloatQuad> quads;
   GetBorderAndTextQuads(quads);
 
-  return ClientRectList::Create(quads);
+  return DOMRectList::Create(quads);
 }
 
-ClientRect* Range::getBoundingClientRect() const {
-  return ClientRect::Create(BoundingRect());
+DOMRect* Range::getBoundingClientRect() const {
+  return DOMRect::FromFloatRect(BoundingRect());
 }
 
 void Range::GetBorderAndTextQuads(Vector<FloatQuad>& quads) const {
diff --git a/third_party/WebKit/Source/core/dom/Range.h b/third_party/WebKit/Source/core/dom/Range.h
index 8ba10fbe..1ac69b4 100644
--- a/third_party/WebKit/Source/core/dom/Range.h
+++ b/third_party/WebKit/Source/core/dom/Range.h
@@ -37,8 +37,8 @@
 
 namespace blink {
 
-class ClientRect;
-class ClientRectList;
+class DOMRect;
+class DOMRectList;
 class ContainerNode;
 class Document;
 class DocumentFragment;
@@ -160,8 +160,8 @@
   // for details.
   void expand(const String&, ExceptionState&);
 
-  ClientRectList* getClientRects() const;
-  ClientRect* getBoundingClientRect() const;
+  DOMRectList* getClientRects() const;
+  DOMRect* getBoundingClientRect() const;
 
   static Node* CheckNodeWOffset(Node*, unsigned offset, ExceptionState&);
 
diff --git a/third_party/WebKit/Source/core/dom/Range.idl b/third_party/WebKit/Source/core/dom/Range.idl
index bb4d08a..6de3c4d 100644
--- a/third_party/WebKit/Source/core/dom/Range.idl
+++ b/third_party/WebKit/Source/core/dom/Range.idl
@@ -64,10 +64,8 @@
 
     // CSSOM View Module
     // https://dev.w3.org/csswg/cssom-view/#extensions-to-the-range-interface
-    // FIXME: getClientRect() and getBoundingClientRect() should
-    // return DOMRectList and DOMRect respectively.
-    ClientRectList getClientRects();
-    ClientRect getBoundingClientRect();
+    DOMRectList getClientRects();
+    DOMRect getBoundingClientRect();
 
     // DOM Parsing and Serialization
     // https://w3c.github.io/DOM-Parsing/#extensions-to-the-range-interface
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp
index 15b6554..05391a6 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp
+++ b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp
@@ -4,16 +4,16 @@
 
 #include "core/dom/ResizeObserverEntry.h"
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/Element.h"
 #include "core/dom/ResizeObservation.h"
+#include "core/geometry/DOMRectReadOnly.h"
 
 namespace blink {
 
 ResizeObserverEntry::ResizeObserverEntry(Element* target,
                                          const LayoutRect& content_rect)
     : target_(target) {
-  content_rect_ = ClientRect::Create(FloatRect(
+  content_rect_ = DOMRectReadOnly::FromFloatRect(FloatRect(
       FloatPoint(content_rect.Location()), FloatSize(content_rect.Size())));
 }
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.h b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.h
index af71db16..48e4541 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.h
+++ b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.h
@@ -11,7 +11,7 @@
 namespace blink {
 
 class Element;
-class ClientRect;
+class DOMRectReadOnly;
 class LayoutRect;
 
 class ResizeObserverEntry final : public GarbageCollected<ResizeObserverEntry>,
@@ -22,15 +22,13 @@
   ResizeObserverEntry(Element* target, const LayoutRect& content_rect);
 
   Element* target() const { return target_; }
-  // FIXME(atotic): should return DOMRectReadOnly once https://crbug.com/388780
-  // lands
-  ClientRect* contentRect() const { return content_rect_; }
+  DOMRectReadOnly* contentRect() const { return content_rect_; }
 
   DECLARE_VIRTUAL_TRACE();
 
  private:
   Member<Element> target_;
-  Member<ClientRect> content_rect_;
+  Member<DOMRectReadOnly> content_rect_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl
index 1ef8760..29e5d96e 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl
+++ b/third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl
@@ -8,6 +8,5 @@
     RuntimeEnabled=ResizeObserver
 ] interface ResizeObserverEntry {
     readonly attribute Element target;
-    // FIXME(atotic): should return DOMReadOnlyRect once GeometryInterfaces land
-    readonly attribute ClientRect contentRect;
+    readonly attribute DOMRectReadOnly contentRect;
 };
diff --git a/third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp b/third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp
index 851852e..88d4900e 100644
--- a/third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp
+++ b/third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp
@@ -30,12 +30,12 @@
 #include "core/frame/BrowserControls.h"
 
 #include "build/build_config.h"
-#include "core/dom/ClientRect.h"
 #include "core/frame/FrameTestHelpers.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/VisualViewport.h"
 #include "core/frame/WebLocalFrameBase.h"
+#include "core/geometry/DOMRect.h"
 #include "core/page/Page.h"
 #include "platform/testing/URLTestHelpers.h"
 #include "platform/testing/UnitTestHelpers.h"
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 348a1e2..1307f400 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -252,7 +252,7 @@
     case WebFeature::kLegacyProtocolEmbeddedAsSubresource:
       return String::Format(
           "Subresource requests using legacy protocols (like `ftp:`) are "
-          "are blocked. Please deliver web-accessible resources over modern "
+          "blocked. Please deliver web-accessible resources over modern "
           "protocols like HTTPS. See "
           "https://www.chromestatus.com/feature/5709390967472128 for details.");
 
diff --git a/third_party/WebKit/Source/core/frame/DocumentLoadingRenderingTest.cpp b/third_party/WebKit/Source/core/frame/DocumentLoadingRenderingTest.cpp
index 82088d7..1224bd4 100644
--- a/third_party/WebKit/Source/core/frame/DocumentLoadingRenderingTest.cpp
+++ b/third_party/WebKit/Source/core/frame/DocumentLoadingRenderingTest.cpp
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/Document.h"
 #include "core/dom/FrameRequestCallback.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/layout/api/LayoutViewItem.h"
 #include "core/paint/PaintLayer.h"
@@ -412,7 +412,7 @@
 
   // If ignoringPendingStylesheets==true, element should get non-empty rect.
   Element* element = GetDocument().getElementById("test");
-  ClientRect* rect = element->getBoundingClientRect();
+  DOMRect* rect = element->getBoundingClientRect();
   EXPECT_TRUE(rect->width() > 0.f);
   EXPECT_TRUE(rect->height() > 0.f);
 
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
index 1045dbd..814d7ab 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
@@ -247,7 +247,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(animationstart);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(transitionend);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
   DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationstart,
                                          webkitAnimationStart);
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
index b22aace..3b3351e 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
@@ -66,6 +66,11 @@
     return FlooredIntSize(MaximumScrollOffset());
   }
 
+  IntRect VisibleContentRect(
+      IncludeScrollbarsInRect = kExcludeScrollbars) const override {
+    return IntRect(IntPoint(FlooredIntSize(scroll_offset_)), viewport_size_);
+  }
+
   IntSize ContentsSize() const override { return contents_size_; }
   void SetContentSize(const IntSize& contents_size) {
     contents_size_ = contents_size;
diff --git a/third_party/WebKit/Source/core/frame/Window.idl b/third_party/WebKit/Source/core/frame/Window.idl
index f1b8629..3e488fa 100644
--- a/third_party/WebKit/Source/core/frame/Window.idl
+++ b/third_party/WebKit/Source/core/frame/Window.idl
@@ -198,7 +198,6 @@
     attribute EventHandler onwebkitanimationiteration;
     attribute EventHandler onwebkitanimationstart;
     attribute EventHandler onwebkittransitionend;
-    attribute EventHandler onwheel;
 
     // https://w3c.github.io/webappsec/specs/powerfulfeatures/#monkey-patching-global-object
     readonly attribute boolean isSecureContext;
diff --git a/third_party/WebKit/Source/core/geometry/BUILD.gn b/third_party/WebKit/Source/core/geometry/BUILD.gn
index 83905d1..d0293bf 100644
--- a/third_party/WebKit/Source/core/geometry/BUILD.gn
+++ b/third_party/WebKit/Source/core/geometry/BUILD.gn
@@ -20,6 +20,8 @@
     "DOMQuad.h",
     "DOMRect.cpp",
     "DOMRect.h",
+    "DOMRectList.cpp",
+    "DOMRectList.h",
     "DOMRectReadOnly.cpp",
     "DOMRectReadOnly.h",
   ]
diff --git a/third_party/WebKit/Source/core/geometry/DOMRect.cpp b/third_party/WebKit/Source/core/geometry/DOMRect.cpp
index bf1a2e9..5fac2b5e 100644
--- a/third_party/WebKit/Source/core/geometry/DOMRect.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMRect.cpp
@@ -12,6 +12,10 @@
   return new DOMRect(x, y, width, height);
 }
 
+DOMRect* DOMRect::FromFloatRect(const FloatRect& rect) {
+  return new DOMRect(rect.X(), rect.Y(), rect.Width(), rect.Height());
+}
+
 DOMRect* DOMRect::fromRect(const DOMRectInit& other) {
   return new DOMRect(other.x(), other.y(), other.width(), other.height());
 }
diff --git a/third_party/WebKit/Source/core/geometry/DOMRect.h b/third_party/WebKit/Source/core/geometry/DOMRect.h
index 19bd8eb..8f1ad252 100644
--- a/third_party/WebKit/Source/core/geometry/DOMRect.h
+++ b/third_party/WebKit/Source/core/geometry/DOMRect.h
@@ -8,6 +8,7 @@
 #include "bindings/core/v8/Dictionary.h"
 #include "core/CoreExport.h"
 #include "core/geometry/DOMRectReadOnly.h"
+#include "platform/geometry/FloatRect.h"
 
 namespace blink {
 
@@ -22,6 +23,7 @@
                          double y = 0,
                          double width = 0,
                          double height = 0);
+  static DOMRect* FromFloatRect(const FloatRect&);
   static DOMRect* fromRect(const DOMRectInit&);
 
   void setX(double x) { x_ = x; }
diff --git a/third_party/WebKit/Source/core/dom/ClientRectList.cpp b/third_party/WebKit/Source/core/geometry/DOMRectList.cpp
similarity index 83%
rename from third_party/WebKit/Source/core/dom/ClientRectList.cpp
rename to third_party/WebKit/Source/core/geometry/DOMRectList.cpp
index 3ab85cb..f01ddb4 100644
--- a/third_party/WebKit/Source/core/dom/ClientRectList.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMRectList.cpp
@@ -24,30 +24,30 @@
  *
  */
 
-#include "core/dom/ClientRectList.h"
+#include "core/geometry/DOMRectList.h"
 
 namespace blink {
 
-ClientRectList::ClientRectList() {}
+DOMRectList::DOMRectList() {}
 
-ClientRectList::ClientRectList(const Vector<FloatQuad>& quads) {
+DOMRectList::DOMRectList(const Vector<FloatQuad>& quads) {
   list_.ReserveInitialCapacity(quads.size());
   for (const auto& quad : quads)
-    list_.push_back(ClientRect::Create(quad.BoundingBox()));
+    list_.push_back(DOMRect::FromFloatRect(quad.BoundingBox()));
 }
 
-unsigned ClientRectList::length() const {
+unsigned DOMRectList::length() const {
   return list_.size();
 }
 
-ClientRect* ClientRectList::item(unsigned index) {
+DOMRect* DOMRectList::item(unsigned index) {
   if (index >= list_.size())
     return nullptr;
 
   return list_[index].Get();
 }
 
-DEFINE_TRACE(ClientRectList) {
+DEFINE_TRACE(DOMRectList) {
   visitor->Trace(list_);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/ClientRectList.h b/third_party/WebKit/Source/core/geometry/DOMRectList.h
similarity index 68%
rename from third_party/WebKit/Source/core/dom/ClientRectList.h
rename to third_party/WebKit/Source/core/geometry/DOMRectList.h
index 40a1c51..8e41802 100644
--- a/third_party/WebKit/Source/core/dom/ClientRectList.h
+++ b/third_party/WebKit/Source/core/geometry/DOMRectList.h
@@ -24,56 +24,52 @@
  *
  */
 
-#ifndef ClientRectList_h
-#define ClientRectList_h
+#ifndef DOMRectList_h
+#define DOMRectList_h
 
 #include "core/CoreExport.h"
-#include "core/dom/ClientRect.h"
+#include "core/geometry/DOMRect.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/geometry/FloatQuad.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
 
-class ClientRect;
-
-class CORE_EXPORT ClientRectList final
-    : public GarbageCollected<ClientRectList>,
-      public ScriptWrappable {
+class CORE_EXPORT DOMRectList final : public GarbageCollected<DOMRectList>,
+                                      public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static ClientRectList* Create() { return new ClientRectList; }
-  static ClientRectList* Create(const Vector<FloatQuad>& quads) {
-    return new ClientRectList(quads);
+  static DOMRectList* Create() { return new DOMRectList; }
+  static DOMRectList* Create(const Vector<FloatQuad>& quads) {
+    return new DOMRectList(quads);
   }
 
   template <typename Rects>
-  static ClientRectList* Create(const Rects& rects) {
-    return new ClientRectList(rects);
+  static DOMRectList* Create(const Rects& rects) {
+    return new DOMRectList(rects);
   }
 
   unsigned length() const;
-  ClientRect* item(unsigned index);
-  ClientRect* AnonymousIndexedGetter(unsigned index) { return item(index); }
+  DOMRect* item(unsigned index);
 
   DECLARE_TRACE();
 
  private:
-  ClientRectList();
+  DOMRectList();
 
   template <typename Rects>
-  explicit ClientRectList(const Rects& rects) {
+  explicit DOMRectList(const Rects& rects) {
     list_.ReserveInitialCapacity(rects.size());
     for (const auto& r : rects)
-      list_.push_back(ClientRect::Create(FloatRect(r)));
+      list_.push_back(DOMRect::FromFloatRect(FloatRect(r)));
   }
 
-  explicit ClientRectList(const Vector<FloatQuad>&);
+  explicit DOMRectList(const Vector<FloatQuad>&);
 
-  HeapVector<Member<ClientRect>> list_;
+  HeapVector<Member<DOMRect>> list_;
 };
 
 }  // namespace blink
 
-#endif  // ClientRectList_h
+#endif  // DOMRectList_h
diff --git a/third_party/WebKit/Source/core/geometry/DOMRectList.idl b/third_party/WebKit/Source/core/geometry/DOMRectList.idl
new file mode 100644
index 0000000..9cc9d65f
--- /dev/null
+++ b/third_party/WebKit/Source/core/geometry/DOMRectList.idl
@@ -0,0 +1,15 @@
+// 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.
+
+// https://dev.w3.org/fxtf/geometry/#DOMRectList
+// Spec update: https://github.com/w3c/fxtf-drafts/pull/186
+
+// DOMRectList only exists for compatibility with legacy web content.
+// When specifying a new API, use sequence<DOMRect> instead.
+
+// TODO: Spec also includes LegacyArrayClass that our IDL doesn't support yet.
+[ NoInterfaceObject ] interface DOMRectList {
+    readonly attribute unsigned long length;
+    [MeasureAs=ClientRectListItem] getter DOMRect? item(unsigned long index);
+};
diff --git a/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.cpp b/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.cpp
index 3f8c46dc..e0c5635 100644
--- a/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.cpp
@@ -30,6 +30,14 @@
   return result.GetScriptValue();
 }
 
+DOMRectReadOnly* DOMRectReadOnly::FromIntRect(const IntRect& rect) {
+  return new DOMRectReadOnly(rect.X(), rect.Y(), rect.Width(), rect.Height());
+}
+
+DOMRectReadOnly* DOMRectReadOnly::FromFloatRect(const FloatRect& rect) {
+  return new DOMRectReadOnly(rect.X(), rect.Y(), rect.Width(), rect.Height());
+}
+
 DOMRectReadOnly* DOMRectReadOnly::fromRect(const DOMRectInit& other) {
   return new DOMRectReadOnly(other.x(), other.y(), other.width(),
                              other.height());
diff --git a/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.h b/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.h
index c896e9c..e8638c1 100644
--- a/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.h
+++ b/third_party/WebKit/Source/core/geometry/DOMRectReadOnly.h
@@ -7,6 +7,8 @@
 
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
+#include "platform/geometry/FloatRect.h"
+#include "platform/geometry/IntRect.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
@@ -24,6 +26,8 @@
                                  double y,
                                  double width,
                                  double height);
+  static DOMRectReadOnly* FromIntRect(const IntRect&);
+  static DOMRectReadOnly* FromFloatRect(const FloatRect&);
   static DOMRectReadOnly* fromRect(const DOMRectInit&);
 
   double x() const { return x_; }
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index d7a9a68..2393c4d 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -892,7 +892,10 @@
   if (!RuntimeEnabledFeatures::DisplayList2dCanvasEnabled())
     return false;
 
-  return true;
+  // TODO(crbug.com/721727): Due to a rendering regression with display-
+  // list-2d-canvas, this feature is now disabled by default.  For now, the
+  // feature will only be enabled with --force-display-list-2d-canvas.
+  return false;
 }
 
 std::unique_ptr<ImageBufferSurface>
diff --git a/third_party/WebKit/Source/core/html/media/MediaRemotingElements.cpp b/third_party/WebKit/Source/core/html/media/MediaRemotingElements.cpp
index 4e491648..8c1f4c2 100644
--- a/third_party/WebKit/Source/core/html/media/MediaRemotingElements.cpp
+++ b/third_party/WebKit/Source/core/html/media/MediaRemotingElements.cpp
@@ -4,9 +4,9 @@
 
 #include "core/html/media/MediaRemotingElements.h"
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/ShadowRoot.h"
 #include "core/events/MouseEvent.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/input/EventHandler.h"
 #include "platform/text/PlatformLocale.h"
@@ -38,7 +38,7 @@
     DCHECK_EQ(event->type(), EventTypeNames::click);
 
     MouseEvent* mouse_event = ToMouseEvent(event);
-    ClientRect* client_rect = element_->getBoundingClientRect();
+    DOMRect* client_rect = element_->getBoundingClientRect();
     const double x = mouse_event->x();
     const double y = mouse_event->y();
     if (x < client_rect->left() || x > client_rect->right() ||
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
index 7c16eb50..57919818 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
@@ -32,10 +32,10 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "core/dom/ClientRect.h"
 #include "core/dom/DOMTokenList.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/dom/ExceptionCode.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLDivElement.h"
 #include "core/html/track/vtt/VTTParser.h"
 #include "core/html/track/vtt/VTTScanner.h"
@@ -320,12 +320,13 @@
   if (IsScrollingRegion())
     cue_container_->classList().Add(TextTrackCueContainerScrollingClass());
 
-  float region_bottom = region_display_tree_->getBoundingClientRect()->bottom();
+  double region_bottom =
+      region_display_tree_->getBoundingClientRect()->bottom();
 
   // Find first cue that is not entirely displayed and scroll it upwards.
   for (Element& child : ElementTraversal::ChildrenOf(*cue_container_)) {
-    ClientRect* client_rect = child.getBoundingClientRect();
-    float child_bottom = client_rect->bottom();
+    DOMRect* client_rect = child.getBoundingClientRect();
+    double child_bottom = client_rect->bottom();
 
     if (region_bottom >= child_bottom)
       continue;
diff --git a/third_party/WebKit/Source/core/input/TouchActionTest.cpp b/third_party/WebKit/Source/core/input/TouchActionTest.cpp
index b72042e..1833d750 100644
--- a/third_party/WebKit/Source/core/input/TouchActionTest.cpp
+++ b/third_party/WebKit/Source/core/input/TouchActionTest.cpp
@@ -28,8 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "core/dom/ClientRect.h"
-#include "core/dom/ClientRectList.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/dom/ShadowRoot.h"
@@ -39,6 +37,8 @@
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/WebLocalFrameBase.h"
+#include "core/geometry/DOMRect.h"
+#include "core/geometry/DOMRectList.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/HitTestResult.h"
@@ -266,9 +266,9 @@
     // elements with multiple border boxes with other elements in between. Use
     // the first border box (which we can easily visualize in a browser for
     // debugging).
-    Persistent<ClientRectList> rects = element->getClientRects();
+    Persistent<DOMRectList> rects = element->getClientRects();
     ASSERT_GE(rects->length(), 0u) << failure_context;
-    Persistent<ClientRect> r = rects->item(0);
+    Persistent<DOMRect> r = rects->item(0);
     FloatRect client_float_rect =
         FloatRect(r->left(), r->top(), r->width(), r->height());
     IntRect client_rect = EnclosedIntRect(client_float_rect);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
index 896fb77..6dbfa1f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
@@ -4,9 +4,9 @@
 
 #include "core/inspector/InspectorHighlight.h"
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/PseudoElement.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/geometry/DOMRect.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutObject.h"
@@ -220,7 +220,7 @@
 
   // layoutObject the getBoundingClientRect() data in the tooltip
   // to be consistent with the rulers (see http://crbug.com/262338).
-  ClientRect* bounding_box = element->getBoundingClientRect();
+  DOMRect* bounding_box = element->getBoundingClientRect();
   element_info->setString("nodeWidth", String::Number(bounding_box->width()));
   element_info->setString("nodeHeight", String::Number(bounding_box->height()));
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index a6327cb..809a631 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -5729,7 +5729,7 @@
     return true;
 
   // Our fill layers are ok. Let's check border.
-  if (Style()->HasBorderDecoration() && CanRenderBorderImage())
+  if (Style()->CanRenderBorderImage())
     return true;
 
   return false;
@@ -5748,20 +5748,12 @@
     return true;
 
   // Our fill layers are ok.  Let's check border.
-  if (Style()->HasBorderDecoration() && CanRenderBorderImage())
+  if (Style()->CanRenderBorderImage())
     return true;
 
   return false;
 }
 
-bool LayoutBox::CanRenderBorderImage() const {
-  if (!Style()->HasBorderDecoration())
-    return false;
-
-  StyleImage* border_image = Style()->BorderImage().GetImage();
-  return border_image && border_image->CanRender() && border_image->IsLoaded();
-}
-
 ShapeOutsideInfo* LayoutBox::GetShapeOutsideInfo() const {
   return ShapeOutsideInfo::IsEnabledFor(*this) ? ShapeOutsideInfo::Info(*this)
                                                : nullptr;
diff --git a/third_party/WebKit/Source/core/layout/ScrollAnchorTest.cpp b/third_party/WebKit/Source/core/layout/ScrollAnchorTest.cpp
index 344d0c6..d34f472 100644
--- a/third_party/WebKit/Source/core/layout/ScrollAnchorTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollAnchorTest.cpp
@@ -4,8 +4,8 @@
 
 #include "core/layout/ScrollAnchor.h"
 
-#include "core/dom/ClientRect.h"
 #include "core/frame/VisualViewport.h"
+#include "core/geometry/DOMRect.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutTestHelper.h"
 #include "core/page/PrintContext.h"
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index fd58c422..2a04d2e0 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -1211,7 +1211,7 @@
         RoundedIntPoint(compositing_container->SubpixelAccumulation());
   } else if (compositing_container) {
     graphics_layer_parent_location = ancestor_compositing_bounds.Location();
-  } else {
+  } else if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     graphics_layer_parent_location =
         GetLayoutObject().View()->DocumentRect().Location();
   }
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 7473695..17f01a7 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -23,7 +23,6 @@
 
 #include "bindings/core/v8/ScriptController.h"
 #include "core/css/resolver/ViewportStyleResolver.h"
-#include "core/dom/ClientRectList.h"
 #include "core/dom/StyleChangeReason.h"
 #include "core/dom/StyleEngine.h"
 #include "core/dom/VisitedLinkState.h"
@@ -41,6 +40,7 @@
 #include "core/frame/RemoteFrameView.h"
 #include "core/frame/Settings.h"
 #include "core/frame/VisualViewport.h"
+#include "core/geometry/DOMRectList.h"
 #include "core/html/HTMLMediaElement.h"
 #include "core/inspector/ConsoleMessageStorage.h"
 #include "core/layout/TextAutosizer.h"
@@ -229,7 +229,7 @@
   return *overscroll_controller_;
 }
 
-ClientRectList* Page::NonFastScrollableRects(const LocalFrame* frame) {
+DOMRectList* Page::NonFastScrollableRects(const LocalFrame* frame) {
   DisableCompositingQueryAsserts disabler;
   if (ScrollingCoordinator* scrolling_coordinator =
           this->GetScrollingCoordinator()) {
@@ -240,9 +240,8 @@
   GraphicsLayer* layer =
       frame->View()->LayoutViewportScrollableArea()->LayerForScrolling();
   if (!layer)
-    return ClientRectList::Create();
-  return ClientRectList::Create(
-      layer->PlatformLayer()->NonFastScrollableRegion());
+    return DOMRectList::Create();
+  return DOMRectList::Create(layer->PlatformLayer()->NonFastScrollableRegion());
 }
 
 void Page::SetMainFrame(Frame* main_frame) {
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index cc00c32..f854ba7b 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -50,10 +50,10 @@
 class AutoscrollController;
 class BrowserControls;
 class ChromeClient;
-class ClientRectList;
 class ContextMenuClient;
 class ContextMenuController;
 class Document;
+class DOMRectList;
 class DragCaret;
 class DragController;
 class EditorClient;
@@ -188,7 +188,7 @@
 
   SmoothScrollSequencer* GetSmoothScrollSequencer();
 
-  ClientRectList* NonFastScrollableRects(const LocalFrame*);
+  DOMRectList* NonFastScrollableRects(const LocalFrame*);
 
   Settings& GetSettings() const { return *settings_; }
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
index 00d33688..869ab04 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "bindings/core/v8/NodeOrString.h"
-#include "core/dom/ClientRect.h"
 #include "core/exported/WebRemoteFrameImpl.h"
 #include "core/frame/BrowserControls.h"
 #include "core/frame/FrameTestHelpers.h"
@@ -11,6 +10,7 @@
 #include "core/frame/RootFrameViewport.h"
 #include "core/frame/VisualViewport.h"
 #include "core/frame/WebLocalFrameBase.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/api/LayoutViewItem.h"
@@ -1039,7 +1039,7 @@
   MainFrameView()->UpdateAllLifecyclePhases();
 
   // The visual viewport should remain fully filled by the target.
-  ClientRect* rect = target->getBoundingClientRect();
+  DOMRect* rect = target->getBoundingClientRect();
   EXPECT_EQ(rect->left(), GetVisualViewport().GetScrollOffset().Width());
   EXPECT_EQ(rect->top(), GetVisualViewport().GetScrollOffset().Height());
 }
diff --git a/third_party/WebKit/Source/core/paint/BoxDecorationData.cpp b/third_party/WebKit/Source/core/paint/BoxDecorationData.cpp
index 92b3573..05da6a0 100644
--- a/third_party/WebKit/Source/core/paint/BoxDecorationData.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxDecorationData.cpp
@@ -21,7 +21,13 @@
   DCHECK(has_background == layout_box.Style()->HasBackground());
   has_border_decoration = layout_box.Style()->HasBorderDecoration();
   has_appearance = layout_box.Style()->HasAppearance();
-  bleed_avoidance = DetermineBackgroundBleedAvoidance(layout_box);
+  if (layout_box.IsDocumentElement()) {
+    bleed_avoidance = kBackgroundBleedNone;
+  } else {
+    bleed_avoidance = DetermineBackgroundBleedAvoidance(
+        layout_box.GetDocument(), layout_box.StyleRef(),
+        layout_box.BackgroundShouldAlwaysBeClipped());
+  }
 }
 
 namespace {
@@ -41,37 +47,34 @@
 }  // anonymous namespace
 
 BackgroundBleedAvoidance BoxDecorationData::DetermineBackgroundBleedAvoidance(
-    const LayoutBox& layout_box) {
-  if (layout_box.IsDocumentElement())
-    return kBackgroundBleedNone;
-
+    const Document& document,
+    const ComputedStyle& style,
+    bool background_should_always_be_clipped) {
   if (!has_background)
     return kBackgroundBleedNone;
 
-  const ComputedStyle& box_style = layout_box.StyleRef();
-  const bool has_border_radius = box_style.HasBorderRadius();
+  const bool has_border_radius = style.HasBorderRadius();
   if (!has_border_decoration || !has_border_radius ||
-      layout_box.CanRenderBorderImage()) {
-    if (layout_box.BackgroundShouldAlwaysBeClipped())
+      style.CanRenderBorderImage()) {
+    if (background_should_always_be_clipped)
       return kBackgroundBleedClipOnly;
     // Border radius clipping may require layer bleed avoidance if we are going
     // to draw an image over something else, because we do not want the
     // antialiasing to lead to bleeding
-    if (box_style.HasBackgroundImage() && has_border_radius) {
+    if (style.HasBackgroundImage() && has_border_radius) {
       // But if the top layer is opaque for the purposes of background painting,
       // we do not need the bleed avoidance because we will not paint anything
       // behind the top layer.  But only if we need to draw something
       // underneath.
-      const FillLayer& fill_layer = layout_box.Style()->BackgroundLayers();
+      const FillLayer& fill_layer = style.BackgroundLayers();
       if ((background_color.Alpha() || fill_layer.Next()) &&
-          !fill_layer.ImageOccludesNextLayers(layout_box.GetDocument(),
-                                              box_style))
+          !fill_layer.ImageOccludesNextLayers(document, style))
         return kBackgroundBleedClipLayer;
     }
     return kBackgroundBleedNone;
   }
 
-  if (BorderObscuresBackgroundEdge(box_style))
+  if (BorderObscuresBackgroundEdge(style))
     return kBackgroundBleedShrinkBackground;
 
   return kBackgroundBleedClipLayer;
diff --git a/third_party/WebKit/Source/core/paint/BoxDecorationData.h b/third_party/WebKit/Source/core/paint/BoxDecorationData.h
index e66c5e29..9df73be 100644
--- a/third_party/WebKit/Source/core/paint/BoxDecorationData.h
+++ b/third_party/WebKit/Source/core/paint/BoxDecorationData.h
@@ -11,6 +11,8 @@
 namespace blink {
 
 class LayoutBox;
+class Document;
+class ComputedStyle;
 
 // Information extracted from ComputedStyle for box painting.
 struct BoxDecorationData {
@@ -26,7 +28,10 @@
   bool has_appearance;
 
  private:
-  BackgroundBleedAvoidance DetermineBackgroundBleedAvoidance(const LayoutBox&);
+  BackgroundBleedAvoidance DetermineBackgroundBleedAvoidance(
+      const Document&,
+      const ComputedStyle&,
+      bool background_should_always_be_clipped);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
index 028cbbd..39876b9 100644
--- a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
@@ -12,12 +12,12 @@
 namespace blink {
 
 RoundedInnerRectClipper::RoundedInnerRectClipper(
-    const DisplayItemClient& layout_object,
+    const DisplayItemClient& display_item,
     const PaintInfo& paint_info,
     const LayoutRect& rect,
     const FloatRoundedRect& clip_rect,
     RoundedInnerRectClipperBehavior behavior)
-    : layout_object_(layout_object),
+    : display_item_(display_item),
       paint_info_(paint_info),
       use_paint_controller_(behavior == kApplyToDisplayList),
       clip_type_(use_paint_controller_
@@ -73,7 +73,7 @@
 
   if (use_paint_controller_) {
     paint_info_.context.GetPaintController().CreateAndAppend<ClipDisplayItem>(
-        layout_object, clip_type_, LayoutRect::InfiniteIntRect(),
+        display_item, clip_type_, LayoutRect::InfiniteIntRect(),
         rounded_rect_clips);
   } else {
     paint_info.context.Save();
@@ -89,7 +89,7 @@
   DisplayItem::Type end_type = DisplayItem::ClipTypeToEndClipType(clip_type_);
   if (use_paint_controller_) {
     paint_info_.context.GetPaintController().EndItem<EndClipDisplayItem>(
-        layout_object_, end_type);
+        display_item_, end_type);
   } else {
     paint_info_.context.Restore();
   }
diff --git a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h
index 2b1f5fe..2a691f08 100644
--- a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h
+++ b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h
@@ -29,7 +29,7 @@
   ~RoundedInnerRectClipper();
 
  private:
-  const DisplayItemClient& layout_object_;
+  const DisplayItemClient& display_item_;
   const PaintInfo& paint_info_;
   bool use_paint_controller_;
   DisplayItem::Type clip_type_;
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 4c4bb52..78ecea0 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -1096,6 +1096,14 @@
   return rounded_rect;
 }
 
+bool ComputedStyle::CanRenderBorderImage() const {
+  if (!HasBorderDecoration())
+    return false;
+
+  StyleImage* border_image = BorderImage().GetImage();
+  return border_image && border_image->CanRender() && border_image->IsLoaded();
+}
+
 static bool AllLayersAreFixed(const FillLayer& layer) {
   for (const FillLayer* curr_layer = &layer; curr_layer;
        curr_layer = curr_layer->Next()) {
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index e38b036..c2a551b1 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1812,6 +1812,8 @@
       bool include_logical_left_edge,
       bool include_logical_right_edge) const;
 
+  bool CanRenderBorderImage() const;
+
   // Float utility functions.
   bool IsFloating() const { return Floating() != EFloat::kNone; }
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 73fae78a..b526c21c 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -41,8 +41,6 @@
 #include "core/StylePropertyShorthand.h"
 #include "core/animation/DocumentTimeline.h"
 #include "core/css/CSSPropertyMetadata.h"
-#include "core/dom/ClientRect.h"
-#include "core/dom/ClientRectList.h"
 #include "core/dom/DOMArrayBuffer.h"
 #include "core/dom/DOMNodeIds.h"
 #include "core/dom/DOMStringList.h"
@@ -82,6 +80,8 @@
 #include "core/frame/Settings.h"
 #include "core/frame/VisualViewport.h"
 #include "core/geometry/DOMPoint.h"
+#include "core/geometry/DOMRect.h"
+#include "core/geometry/DOMRectList.h"
 #include "core/html/HTMLContentElement.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLImageElement.h"
@@ -885,15 +885,17 @@
   return nullptr;
 }
 
-ClientRect* Internals::absoluteCaretBounds(ExceptionState& exception_state) {
+DOMRectReadOnly* Internals::absoluteCaretBounds(
+    ExceptionState& exception_state) {
   if (!GetFrame()) {
     exception_state.ThrowDOMException(
         kInvalidAccessError, "The document's frame cannot be retrieved.");
-    return ClientRect::Create();
+    return nullptr;
   }
 
   document_->UpdateStyleAndLayoutIgnorePendingStylesheets();
-  return ClientRect::Create(GetFrame()->Selection().AbsoluteCaretBounds());
+  return DOMRectReadOnly::FromIntRect(
+      GetFrame()->Selection().AbsoluteCaretBounds());
 }
 
 String Internals::textAffinity() {
@@ -909,14 +911,14 @@
   return "Downstream";
 }
 
-ClientRect* Internals::boundingBox(Element* element) {
+DOMRectReadOnly* Internals::boundingBox(Element* element) {
   DCHECK(element);
 
   element->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
   LayoutObject* layout_object = element->GetLayoutObject();
   if (!layout_object)
-    return ClientRect::Create();
-  return ClientRect::Create(
+    return DOMRectReadOnly::Create(0, 0, 0, 0);
+  return DOMRectReadOnly::FromIntRect(
       layout_object->AbsoluteBoundingBoxRectIgnoringTransforms());
 }
 
@@ -1516,7 +1518,7 @@
   return target_node;
 }
 
-ClientRect* Internals::bestZoomableAreaForTouchPoint(
+DOMRectReadOnly* Internals::bestZoomableAreaForTouchPoint(
     long x,
     long y,
     long width,
@@ -1541,7 +1543,7 @@
       document->GetFrame()->GetEventHandler().BestZoomableAreaForTouchPoint(
           point, radius, zoomable_area, target_node);
   if (found_node)
-    return ClientRect::Create(zoomable_area);
+    return DOMRectReadOnly::FromIntRect(zoomable_area);
 
   return nullptr;
 }
@@ -1866,7 +1868,7 @@
       if (!layer_rects[i].IsEmpty()) {
         rects->Append(node, layer_type, layer_offset.Width(),
                       layer_offset.Height(),
-                      ClientRect::Create(layer_rects[i]));
+                      DOMRectReadOnly::FromIntRect(layer_rects[i]));
       }
     }
   }
@@ -2236,7 +2238,7 @@
   return document->GetFrame()->View()->MainThreadScrollingReasonsAsText();
 }
 
-ClientRectList* Internals::nonFastScrollableRects(
+DOMRectList* Internals::nonFastScrollableRects(
     Document* document,
     ExceptionState& exception_state) const {
   DCHECK(document);
@@ -2572,25 +2574,24 @@
     layout_view_item.InvalidatePaintForViewAndCompositedLayers();
 }
 
-ClientRectList* Internals::draggableRegions(Document* document,
-                                            ExceptionState& exception_state) {
+DOMRectList* Internals::draggableRegions(Document* document,
+                                         ExceptionState& exception_state) {
   return AnnotatedRegions(document, true, exception_state);
 }
 
-ClientRectList* Internals::nonDraggableRegions(
-    Document* document,
-    ExceptionState& exception_state) {
+DOMRectList* Internals::nonDraggableRegions(Document* document,
+                                            ExceptionState& exception_state) {
   return AnnotatedRegions(document, false, exception_state);
 }
 
-ClientRectList* Internals::AnnotatedRegions(Document* document,
-                                            bool draggable,
-                                            ExceptionState& exception_state) {
+DOMRectList* Internals::AnnotatedRegions(Document* document,
+                                         bool draggable,
+                                         ExceptionState& exception_state) {
   DCHECK(document);
   if (!document->View()) {
     exception_state.ThrowDOMException(kInvalidAccessError,
                                       "The document provided is invalid.");
-    return ClientRectList::Create();
+    return DOMRectList::Create();
   }
 
   document->UpdateStyleAndLayout();
@@ -2602,7 +2603,7 @@
     if (regions[i].draggable == draggable)
       quads.push_back(FloatQuad(FloatRect(regions[i].bounds)));
   }
-  return ClientRectList::Create(quads);
+  return DOMRectList::Create(quads);
 }
 
 static const char* CursorTypeToString(Cursor::Type cursor_type) {
@@ -2831,14 +2832,14 @@
   return position.IsNull() ? 0 : position.ComputeOffsetInContainerNode();
 }
 
-ClientRect* Internals::selectionBounds(ExceptionState& exception_state) {
+DOMRect* Internals::selectionBounds(ExceptionState& exception_state) {
   if (!GetFrame()) {
     exception_state.ThrowDOMException(
         kInvalidAccessError, "The document's frame cannot be retrieved.");
     return nullptr;
   }
 
-  return ClientRect::Create(FloatRect(GetFrame()->Selection().Bounds()));
+  return DOMRect::FromFloatRect(FloatRect(GetFrame()->Selection().Bounds()));
 }
 
 String Internals::markerTextForListItem(Element* element) {
@@ -3348,20 +3349,20 @@
   return "unscopableMethod";
 }
 
-ClientRectList* Internals::focusRingRects(Element* element) {
+DOMRectList* Internals::focusRingRects(Element* element) {
   Vector<LayoutRect> rects;
   if (element && element->GetLayoutObject())
     element->GetLayoutObject()->AddOutlineRects(
         rects, LayoutPoint(), LayoutObject::kIncludeBlockVisualOverflow);
-  return ClientRectList::Create(rects);
+  return DOMRectList::Create(rects);
 }
 
-ClientRectList* Internals::outlineRects(Element* element) {
+DOMRectList* Internals::outlineRects(Element* element) {
   Vector<LayoutRect> rects;
   if (element && element->GetLayoutObject())
     element->GetLayoutObject()->AddOutlineRects(
         rects, LayoutPoint(), LayoutObject::kDontIncludeBlockVisualOverflow);
-  return ClientRectList::Create(rects);
+  return DOMRectList::Create(rects);
 }
 
 void Internals::setCapsLockState(bool enabled) {
@@ -3399,11 +3400,12 @@
   return String();
 }
 
-ClientRect* Internals::visualRect(Node* node) {
+DOMRect* Internals::visualRect(Node* node) {
   if (!node || !node->GetLayoutObject())
-    return ClientRect::Create();
+    return DOMRect::Create();
 
-  return ClientRect::Create(FloatRect(node->GetLayoutObject()->VisualRect()));
+  return DOMRect::FromFloatRect(
+      FloatRect(node->GetLayoutObject()->VisualRect()));
 }
 
 void Internals::crash() {
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index ebbf5ca..7a78f35 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -43,8 +43,9 @@
 class Animation;
 class CallbackFunctionTest;
 class CanvasRenderingContext;
-class ClientRect;
-class ClientRectList;
+class DOMRect;
+class DOMRectList;
+class DOMRectReadOnly;
 class DOMArrayBuffer;
 class DOMPoint;
 class DOMWindow;
@@ -173,9 +174,9 @@
   void setFormControlStateOfHistoryItem(const Vector<String>&, ExceptionState&);
   DOMWindow* pagePopupWindow() const;
 
-  ClientRect* absoluteCaretBounds(ExceptionState&);
+  DOMRectReadOnly* absoluteCaretBounds(ExceptionState&);
 
-  ClientRect* boundingBox(Element*);
+  DOMRectReadOnly* boundingBox(Element*);
 
   void setMarker(Document*, const Range*, const String&, ExceptionState&);
   unsigned markerCountForNode(Node*, const String&, ExceptionState&);
@@ -251,12 +252,12 @@
                                                long height,
                                                Document*,
                                                ExceptionState&);
-  ClientRect* bestZoomableAreaForTouchPoint(long x,
-                                            long y,
-                                            long width,
-                                            long height,
-                                            Document*,
-                                            ExceptionState&);
+  DOMRectReadOnly* bestZoomableAreaForTouchPoint(long x,
+                                                 long y,
+                                                 long width,
+                                                 long height,
+                                                 Document*,
+                                                 ExceptionState&);
 
   int lastSpellCheckRequestSequence(Document*, ExceptionState&);
   int lastSpellCheckProcessedSequence(Document*, ExceptionState&);
@@ -337,7 +338,7 @@
 
   String scrollingStateTreeAsText(Document*) const;
   String mainThreadScrollingReasons(Document*, ExceptionState&) const;
-  ClientRectList* nonFastScrollableRects(Document*, ExceptionState&) const;
+  DOMRectList* nonFastScrollableRects(Document*, ExceptionState&) const;
 
   void evictAllResources() const;
 
@@ -409,8 +410,8 @@
       ExceptionState&);
   void forceFullRepaint(Document*, ExceptionState&);
 
-  ClientRectList* draggableRegions(Document*, ExceptionState&);
-  ClientRectList* nonDraggableRegions(Document*, ExceptionState&);
+  DOMRectList* draggableRegions(Document*, ExceptionState&);
+  DOMRectList* nonDraggableRegions(Document*, ExceptionState&);
 
   DOMArrayBuffer* serializeObject(PassRefPtr<SerializedScriptValue>) const;
   PassRefPtr<SerializedScriptValue> deserializeBuffer(DOMArrayBuffer*) const;
@@ -440,7 +441,7 @@
   unsigned visibleSelectionAnchorOffset();
   Node* visibleSelectionFocusNode();
   unsigned visibleSelectionFocusOffset();
-  ClientRect* selectionBounds(ExceptionState&);
+  DOMRect* selectionBounds(ExceptionState&);
   String textAffinity();
 
   bool loseSharedGraphicsContext3D();
@@ -538,8 +539,8 @@
   String unscopableAttribute();
   String unscopableMethod();
 
-  ClientRectList* focusRingRects(Element*);
-  ClientRectList* outlineRects(Element*);
+  DOMRectList* focusRingRects(Element*);
+  DOMRectList* outlineRects(Element*);
 
   void setCapsLockState(bool enabled);
 
@@ -560,7 +561,7 @@
   String getProgrammaticScrollAnimationState(Node*) const;
 
   // Returns the visual rect of a node's LayoutObject.
-  ClientRect* visualRect(Node*);
+  DOMRect* visualRect(Node*);
 
   // Intentional crash.
   void crash();
@@ -575,7 +576,7 @@
   Document* ContextDocument() const;
   LocalFrame* GetFrame() const;
   Vector<String> IconURLs(Document*, int icon_types_mask) const;
-  ClientRectList* AnnotatedRegions(Document*, bool draggable, ExceptionState&);
+  DOMRectList* AnnotatedRegions(Document*, bool draggable, ExceptionState&);
 
   DocumentMarker* MarkerAt(Node*,
                            const String& marker_type,
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index 1a30806..53ace24 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -108,9 +108,9 @@
     [RaisesException] void setFormControlStateOfHistoryItem(sequence<DOMString> values);
     readonly attribute Window pagePopupWindow;
 
-    [RaisesException] ClientRect absoluteCaretBounds();
+    [RaisesException] DOMRectReadOnly absoluteCaretBounds();
 
-    ClientRect boundingBox(Element element);
+    DOMRectReadOnly boundingBox(Element element);
 
     [RaisesException] void setMarker(Document document, Range range, DOMString markerType);
     [RaisesException] unsigned long markerCountForNode(Node node, DOMString markerType);
@@ -145,7 +145,7 @@
     [RaisesException] Node touchNodeAdjustedToBestClickableNode(long x, long y, long width, long height, Document document);
     [RaisesException] DOMPoint touchPositionAdjustedToBestContextMenuNode(long x, long y, long width, long height, Document document);
     [RaisesException] Node touchNodeAdjustedToBestContextMenuNode(long x, long y, long width, long height, Document document);
-    [RaisesException] ClientRect bestZoomableAreaForTouchPoint(long x, long y, long width, long height, Document document);
+    [RaisesException] DOMRectReadOnly bestZoomableAreaForTouchPoint(long x, long y, long width, long height, Document document);
 
     [RaisesException] long lastSpellCheckRequestSequence(Document document);
     [RaisesException] long lastSpellCheckProcessedSequence(Document document);
@@ -212,7 +212,7 @@
 
     DOMString scrollingStateTreeAsText(Document document);
     [RaisesException] DOMString mainThreadScrollingReasons(Document document);
-    [RaisesException] ClientRectList nonFastScrollableRects(Document document);
+    [RaisesException] DOMRectList nonFastScrollableRects(Document document);
 
     void evictAllResources();
 
@@ -261,8 +261,8 @@
     [RaisesException] void forceFullRepaint(Document document);
 
     // Returns a list of draggable/non-draggable regions in the document.
-    [RaisesException] ClientRectList draggableRegions(Document document);
-    [RaisesException] ClientRectList nonDraggableRegions(Document document);
+    [RaisesException] DOMRectList draggableRegions(Document document);
+    [RaisesException] DOMRectList nonDraggableRegions(Document document);
 
     // Returns a string with information about the mouse cursor used at the specified client location.
     DOMString getCurrentCursorInfo();
@@ -293,7 +293,7 @@
     readonly attribute unsigned long visibleSelectionAnchorOffset;
     readonly attribute Node? visibleSelectionFocusNode;
     readonly attribute unsigned long visibleSelectionFocusOffset;
-    [RaisesException] ClientRect selectionBounds();
+    [RaisesException] DOMRect selectionBounds();
     readonly attribute DOMString textAffinity;
 
     boolean loseSharedGraphicsContext3D();
@@ -373,8 +373,8 @@
     [Unscopable] readonly attribute DOMString unscopableAttribute;
     [Unscopable] DOMString unscopableMethod();
 
-    ClientRectList focusRingRects(Element element);
-    ClientRectList outlineRects(Element element);
+    DOMRectList focusRingRects(Element element);
+    DOMRectList outlineRects(Element element);
     void setCapsLockState(boolean enabled);
 
     // Returns whether the scrollbar was able to be shown or hidden; not all platforms
@@ -387,7 +387,7 @@
 
     DOMString getProgrammaticScrollAnimationState(Node node);
 
-    ClientRect visualRect(Node node);
+    DOMRect visualRect(Node node);
 
     OriginTrialsTest originTrialsTest();
 
diff --git a/third_party/WebKit/Source/core/testing/LayerRect.h b/third_party/WebKit/Source/core/testing/LayerRect.h
index c91f073..93acd506 100644
--- a/third_party/WebKit/Source/core/testing/LayerRect.h
+++ b/third_party/WebKit/Source/core/testing/LayerRect.h
@@ -31,8 +31,8 @@
 #ifndef LayerRect_h
 #define LayerRect_h
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/Node.h"
+#include "core/geometry/DOMRectReadOnly.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/text/WTFString.h"
@@ -48,7 +48,7 @@
                            const String& layer_type,
                            int node_offset_x,
                            int node_offset_y,
-                           ClientRect* rect) {
+                           DOMRectReadOnly* rect) {
     return new LayerRect(node, layer_type, node_offset_x, node_offset_y, rect);
   }
 
@@ -56,7 +56,7 @@
   String layerType() const { return layer_type_; }
   int associatedNodeOffsetX() const { return associated_node_offset_x_; }
   int associatedNodeOffsetY() const { return associated_node_offset_y_; }
-  ClientRect* layerRelativeRect() const { return rect_.Get(); }
+  DOMRectReadOnly* layerRelativeRect() const { return rect_.Get(); }
 
   DEFINE_INLINE_TRACE() {
     visitor->Trace(layer_associated_node_);
@@ -68,7 +68,7 @@
             const String& layer_name,
             int node_offset_x,
             int node_offset_y,
-            ClientRect* rect)
+            DOMRectReadOnly* rect)
       : layer_associated_node_(node),
         layer_type_(layer_name),
         associated_node_offset_x_(node_offset_x),
@@ -79,7 +79,7 @@
   String layer_type_;
   int associated_node_offset_x_;
   int associated_node_offset_y_;
-  Member<ClientRect> rect_;
+  Member<DOMRectReadOnly> rect_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/LayerRect.idl b/third_party/WebKit/Source/core/testing/LayerRect.idl
index c3f60d4..8556f412 100644
--- a/third_party/WebKit/Source/core/testing/LayerRect.idl
+++ b/third_party/WebKit/Source/core/testing/LayerRect.idl
@@ -39,5 +39,5 @@
     readonly attribute long associatedNodeOffsetX;
     readonly attribute long associatedNodeOffsetY;
     /* Rectange in the GraphicsLayer co-ordinate space */
-    readonly attribute ClientRect layerRelativeRect;
+    readonly attribute DOMRectReadOnly layerRelativeRect;
 };
diff --git a/third_party/WebKit/Source/core/testing/LayerRectList.cpp b/third_party/WebKit/Source/core/testing/LayerRectList.cpp
index 6f0f0ac..bdf90e6 100644
--- a/third_party/WebKit/Source/core/testing/LayerRectList.cpp
+++ b/third_party/WebKit/Source/core/testing/LayerRectList.cpp
@@ -30,8 +30,8 @@
 
 #include "core/testing/LayerRectList.h"
 
-#include "core/dom/ClientRect.h"
 #include "core/dom/Node.h"
+#include "core/geometry/DOMRectReadOnly.h"
 #include "core/testing/LayerRect.h"
 
 namespace blink {
@@ -53,7 +53,7 @@
                            const String& layer_type,
                            int layer_offset_x,
                            int layer_offset_y,
-                           ClientRect* layer_relative_rect) {
+                           DOMRectReadOnly* layer_relative_rect) {
   list_.push_back(LayerRect::Create(layer_root_node, layer_type, layer_offset_x,
                                     layer_offset_y, layer_relative_rect));
 }
diff --git a/third_party/WebKit/Source/core/testing/LayerRectList.h b/third_party/WebKit/Source/core/testing/LayerRectList.h
index 25f1006..b403653 100644
--- a/third_party/WebKit/Source/core/testing/LayerRectList.h
+++ b/third_party/WebKit/Source/core/testing/LayerRectList.h
@@ -38,7 +38,7 @@
 
 namespace blink {
 
-class ClientRect;
+class DOMRectReadOnly;
 class LayerRect;
 class Node;
 
@@ -55,7 +55,7 @@
               const String& layer_name,
               int layer_offset_x,
               int layer_offset_y,
-              ClientRect* layer_relative_rect);
+              DOMRectReadOnly* layer_relative_rect);
 
   DECLARE_TRACE();
 
@@ -67,4 +67,4 @@
 
 }  // namespace blink
 
-#endif  // ClientRectList_h
+#endif  // LayerRectList_h
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
index f40b0a6..7124518d 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationPanelSidebar.js
@@ -57,7 +57,6 @@
     this._applicationTreeElement.appendChild(clearStorageTreeElement);
 
     var storageTreeElement = this._addSidebarSection(Common.UIString('Storage'));
-    this._addRefreshSectionButton(storageTreeElement, this._refreshStorageSection.bind(this));
     this.localStorageListTreeElement =
         new Resources.StorageCategoryTreeElement(panel, Common.UIString('Local Storage'), 'LocalStorage');
     var localStorageIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
@@ -84,7 +83,6 @@
     storageTreeElement.appendChild(this.cookieListTreeElement);
 
     var cacheTreeElement = this._addSidebarSection(Common.UIString('Cache'));
-    this._addRefreshSectionButton(cacheTreeElement, this._refreshCacheSection.bind(this));
     this.cacheStorageListTreeElement = new Resources.ServiceWorkerCacheTreeElement(panel);
     cacheTreeElement.appendChild(this.cacheStorageListTreeElement);
     this.applicationCacheListTreeElement =
@@ -133,32 +131,6 @@
   }
 
   /**
-   * @param {!UI.TreeElement} treeElement
-   * @param {function()} refresh
-   */
-  _addRefreshSectionButton(treeElement, refresh) {
-    var refreshIcon = UI.Icon.create('largeicon-refresh', 'sidebar-section-button');
-    refreshIcon.addEventListener('click', refresh, false);
-    treeElement.setTrailingIcons([refreshIcon]);
-  }
-
-  _refreshStorageSection() {
-    var visibleView = this._panel.visibleView;
-    if (visibleView instanceof Resources.DOMStorageItemsView || visibleView instanceof Resources.CookieItemsView) {
-      // Local Storage, Session Storage || Cookies
-      visibleView.refreshItems();
-    } else if (visibleView instanceof Resources.DatabaseTableView) {
-      // Web SQL
-      visibleView.update();
-    }
-    this.indexedDBListTreeElement.refreshIndexedDB();
-  }
-
-  _refreshCacheSection() {
-    this.cacheStorageListTreeElement._refreshCaches();
-  }
-
-  /**
    * @override
    * @param {!SDK.Target} target
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/resourcesSidebar.css b/third_party/WebKit/Source/devtools/front_end/resources/resourcesSidebar.css
index 60783a0..ccebe240 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/resourcesSidebar.css
+++ b/third_party/WebKit/Source/devtools/front_end/resources/resourcesSidebar.css
@@ -26,21 +26,6 @@
     display: none;
 }
 
-li.storage-group-list-item
-.trailing-icons {
-    width: 14px;
-    height: 14px;
-    margin-left: 6px;
-}
-
-li.storage-group-list-item
-.trailing-icons
-.sidebar-section-button {
-    position: relative;
-    top: -1px;
-    left: -8px;
-}
-
 .navigator-tree-item {
     margin: -3px -7px -3px -7px;
 }
diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
index fba227d..a8d3a56 100644
--- a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
@@ -496,46 +496,45 @@
   updating_ = true;
   if (notifier->Options().enableHighAccuracy() && !enable_high_accuracy_) {
     enable_high_accuracy_ = true;
-    if (geolocation_service_)
-      geolocation_service_->SetHighAccuracy(true);
+    if (geolocation_)
+      geolocation_->SetHighAccuracy(true);
   }
-  UpdateGeolocationServiceConnection();
+  UpdateGeolocationConnection();
 }
 
 void Geolocation::StopUpdating() {
   updating_ = false;
-  UpdateGeolocationServiceConnection();
+  UpdateGeolocationConnection();
   enable_high_accuracy_ = false;
 }
 
-void Geolocation::UpdateGeolocationServiceConnection() {
+void Geolocation::UpdateGeolocationConnection() {
   if (!GetExecutionContext() || !GetPage() || !GetPage()->IsPageVisible() ||
       !updating_) {
-    geolocation_service_.reset();
-    disconnected_geolocation_service_ = true;
+    geolocation_.reset();
+    disconnected_geolocation_ = true;
     return;
   }
-  if (geolocation_service_)
+  if (geolocation_)
     return;
 
   GetFrame()->GetInterfaceProvider().GetInterface(
-      mojo::MakeRequest(&geolocation_service_));
-  geolocation_service_.set_connection_error_handler(ConvertToBaseCallback(
-      WTF::Bind(&Geolocation::OnGeolocationConnectionError,
-                WrapWeakPersistent(this))));
+      mojo::MakeRequest(&geolocation_));
+  geolocation_.set_connection_error_handler(ConvertToBaseCallback(WTF::Bind(
+      &Geolocation::OnGeolocationConnectionError, WrapWeakPersistent(this))));
   if (enable_high_accuracy_)
-    geolocation_service_->SetHighAccuracy(true);
+    geolocation_->SetHighAccuracy(true);
   QueryNextPosition();
 }
 
 void Geolocation::QueryNextPosition() {
-  geolocation_service_->QueryNextPosition(ConvertToBaseCallback(
+  geolocation_->QueryNextPosition(ConvertToBaseCallback(
       WTF::Bind(&Geolocation::OnPositionUpdated, WrapPersistent(this))));
 }
 
 void Geolocation::OnPositionUpdated(
     device::mojom::blink::GeopositionPtr position) {
-  disconnected_geolocation_service_ = false;
+  disconnected_geolocation_ = false;
   if (position->valid) {
     last_position_ = CreateGeoposition(*position);
     PositionChanged();
@@ -543,12 +542,12 @@
     HandleError(
         CreatePositionError(position->error_code, position->error_message));
   }
-  if (!disconnected_geolocation_service_)
+  if (!disconnected_geolocation_)
     QueryNextPosition();
 }
 
 void Geolocation::PageVisibilityChanged() {
-  UpdateGeolocationServiceConnection();
+  UpdateGeolocationConnection();
 }
 
 void Geolocation::OnGeolocationConnectionError() {
diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.h b/third_party/WebKit/Source/modules/geolocation/Geolocation.h
index dba2abd..08da6c8 100644
--- a/third_party/WebKit/Source/modules/geolocation/Geolocation.h
+++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.h
@@ -158,11 +158,11 @@
 
   void StopUpdating();
 
-  void UpdateGeolocationServiceConnection();
+  void UpdateGeolocationConnection();
   void QueryNextPosition();
 
   // Attempts to obtain a position for the given notifier, either by using
-  // the cached position or by requesting one from the GeolocationService.
+  // the cached position or by requesting one from the Geolocation.
   // Sets a fatal error if permission is denied or no position can be
   // obtained.
   void StartRequest(GeoNotifier*);
@@ -200,17 +200,17 @@
   };
 
   Permission geolocation_permission_;
-  device::mojom::blink::GeolocationServicePtr geolocation_service_;
+  device::mojom::blink::GeolocationPtr geolocation_;
   bool enable_high_accuracy_ = false;
   mojom::blink::PermissionServicePtr permission_service_;
 
   // Whether a GeoNotifier is waiting for a position update.
   bool updating_ = false;
 
-  // Set to true when m_geolocationService is disconnected. This is used to
-  // detect when m_geolocationService is disconnected and reconnected while
-  // running callbacks in response to a call to onPositionUpdated().
-  bool disconnected_geolocation_service_ = false;
+  // Set to true when |geolocation_| is disconnected. This is used to
+  // detect when |geolocation_| is disconnected and reconnected while
+  // running callbacks in response to a call to OnPositionUpdated().
+  bool disconnected_geolocation_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index cabbe8b..9dda656 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -27,7 +27,6 @@
 #include "modules/media_controls/MediaControlsImpl.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "core/dom/ClientRect.h"
 #include "core/dom/Fullscreen.h"
 #include "core/dom/MutationCallback.h"
 #include "core/dom/MutationObserver.h"
@@ -40,6 +39,7 @@
 #include "core/events/MouseEvent.h"
 #include "core/frame/Settings.h"
 #include "core/frame/UseCounter.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLMediaElement.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/html/media/AutoplayPolicy.h"
@@ -1029,7 +1029,7 @@
   ResetHideMediaControlsTimer();
 }
 
-void MediaControlsImpl::NotifyElementSizeChanged(ClientRect* new_size) {
+void MediaControlsImpl::NotifyElementSizeChanged(DOMRectReadOnly* new_size) {
   // Note that this code permits a bad frame on resize, since it is
   // run after the relayout / paint happens.  It would be great to improve
   // this, but it would be even greater to move this code entirely to
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
index 530b863..c320b22b 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
@@ -27,6 +27,7 @@
 #ifndef MediaControlsImpl_h
 #define MediaControlsImpl_h
 
+#include "core/geometry/DOMRectReadOnly.h"
 #include "core/html/HTMLDivElement.h"
 #include "core/html/media/MediaControls.h"
 #include "modules/ModulesExport.h"
@@ -148,7 +149,7 @@
   void Invalidate(Element*);
 
   // Notify us that our controls enclosure has changed size.
-  void NotifyElementSizeChanged(ClientRect* new_size);
+  void NotifyElementSizeChanged(DOMRectReadOnly* new_size);
 
   explicit MediaControlsImpl(HTMLMediaElement&);
 
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
index 6dc7898d..b54bb85 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
@@ -10,12 +10,12 @@
 #include "build/build_config.h"
 #include "core/HTMLNames.h"
 #include "core/css/StylePropertySet.h"
-#include "core/dom/ClientRect.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/dom/StyleEngine.h"
 #include "core/events/Event.h"
 #include "core/frame/Settings.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLElement.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/input/EventHandler.h"
@@ -669,7 +669,7 @@
   testing::RunPendingTasks();
 
   ASSERT_TRUE(IsElementVisible(*TimelineElement()));
-  ClientRect* timelineRect = TimelineElement()->getBoundingClientRect();
+  DOMRect* timelineRect = TimelineElement()->getBoundingClientRect();
   ASSERT_LT(0, timelineRect->width());
 
   EXPECT_EQ(0, MediaControls().MediaElement().currentTime());
@@ -702,7 +702,7 @@
   testing::RunPendingTasks();
 
   ASSERT_TRUE(IsElementVisible(*TimelineElement()));
-  ClientRect* timeline_rect = TimelineElement()->getBoundingClientRect();
+  DOMRect* timeline_rect = TimelineElement()->getBoundingClientRect();
   ASSERT_LT(0, timeline_rect->width());
 
   EXPECT_EQ(0, MediaControls().MediaElement().currentTime());
@@ -738,7 +738,7 @@
   testing::RunPendingTasks();
 
   ASSERT_TRUE(IsElementVisible(*TimelineElement()));
-  ClientRect* timelineRect = TimelineElement()->getBoundingClientRect();
+  DOMRect* timelineRect = TimelineElement()->getBoundingClientRect();
   ASSERT_LT(0, timelineRect->width());
 
   EXPECT_EQ(0, MediaControls().MediaElement().currentTime());
@@ -775,7 +775,7 @@
   testing::RunPendingTasks();
 
   ASSERT_TRUE(IsElementVisible(*TimelineElement()));
-  ClientRect* timelineRect = TimelineElement()->getBoundingClientRect();
+  DOMRect* timelineRect = TimelineElement()->getBoundingClientRect();
   ASSERT_LT(0, timelineRect->width());
 
   EXPECT_EQ(0, MediaControls().MediaElement().currentTime());
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
index bab9a01..25680ef 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
@@ -5,8 +5,8 @@
 #include "modules/media_controls/elements/MediaControlCastButtonElement.h"
 
 #include "core/InputTypeNames.h"
-#include "core/dom/ClientRect.h"
 #include "core/events/Event.h"
+#include "core/geometry/DOMRect.h"
 #include "core/html/HTMLMediaElement.h"
 #include "modules/media_controls/MediaControlsImpl.h"
 #include "modules/media_controls/elements/MediaControlElementsHelper.h"
@@ -20,7 +20,7 @@
 namespace {
 
 Element* ElementFromCenter(Element& element) {
-  ClientRect* client_rect = element.getBoundingClientRect();
+  DOMRect* client_rect = element.getBoundingClientRect();
   int center_x =
       static_cast<int>((client_rect->left() + client_rect->right()) / 2);
   int center_y =
diff --git a/third_party/WebKit/Source/modules/sensor/AbsoluteOrientationSensor.cpp b/third_party/WebKit/Source/modules/sensor/AbsoluteOrientationSensor.cpp
index 6a2acb87..4031107 100644
--- a/third_party/WebKit/Source/modules/sensor/AbsoluteOrientationSensor.cpp
+++ b/third_party/WebKit/Source/modules/sensor/AbsoluteOrientationSensor.cpp
@@ -30,7 +30,7 @@
     : OrientationSensor(execution_context,
                         options,
                         exception_state,
-                        SensorType::ABSOLUTE_ORIENTATION) {}
+                        SensorType::ABSOLUTE_ORIENTATION_QUATERNION) {}
 
 DEFINE_TRACE(AbsoluteOrientationSensor) {
   OrientationSensor::Trace(visitor);
diff --git a/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp
index 22e97ea..4ad8aa7d 100644
--- a/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp
+++ b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp
@@ -30,7 +30,7 @@
     : OrientationSensor(execution_context,
                         options,
                         exception_state,
-                        SensorType::RELATIVE_ORIENTATION) {}
+                        SensorType::RELATIVE_ORIENTATION_QUATERNION) {}
 
 DEFINE_TRACE(RelativeOrientationSensor) {
   OrientationSensor::Trace(visitor);
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 74bbce27..fbd8d97 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -814,12 +814,6 @@
     "geometry/cg/IntPointCG.cpp",
     "geometry/cg/IntRectCG.cpp",
     "geometry/cg/IntSizeCG.cpp",
-    "geometry/mac/FloatPointMac.mm",
-    "geometry/mac/FloatRectMac.mm",
-    "geometry/mac/FloatSizeMac.mm",
-    "geometry/mac/IntPointMac.mm",
-    "geometry/mac/IntRectMac.mm",
-    "geometry/mac/IntSizeMac.mm",
     "graphics/AcceleratedStaticBitmapImage.cpp",
     "graphics/AcceleratedStaticBitmapImage.h",
     "graphics/BitmapImage.cpp",
diff --git a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
index 0a6c835..e39dc97 100644
--- a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
+++ b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
@@ -35,19 +35,17 @@
 
 void ReverbInputBuffer::Write(const float* source_p, size_t number_of_frames) {
   size_t buffer_length = buffer_.size();
-  bool is_copy_safe = write_index_ + number_of_frames <= buffer_length;
-  DCHECK(is_copy_safe);
-  if (!is_copy_safe)
-    return;
+  size_t index = WriteIndex();
+  size_t new_index = index + number_of_frames;
 
-  memcpy(buffer_.Data() + write_index_, source_p,
-         sizeof(float) * number_of_frames);
+  CHECK_LE(new_index, buffer_length);
 
-  write_index_ += number_of_frames;
-  DCHECK_LE(write_index_, buffer_length);
+  memcpy(buffer_.Data() + index, source_p, sizeof(float) * number_of_frames);
 
-  if (write_index_ >= buffer_length)
-    write_index_ = 0;
+  if (new_index >= buffer_length)
+    new_index = 0;
+
+  SetWriteIndex(new_index);
 }
 
 float* ReverbInputBuffer::DirectReadFrom(int* read_index,
diff --git a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
index e50602c..0645c474a 100644
--- a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
+++ b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
@@ -32,6 +32,7 @@
 #include "platform/PlatformExport.h"
 #include "platform/audio/AudioArray.h"
 #include "platform/wtf/Allocator.h"
+#include "platform/wtf/Atomics.h"
 #include "platform/wtf/Noncopyable.h"
 
 namespace blink {
@@ -52,7 +53,10 @@
   void Write(const float* source_p, size_t number_of_frames);
 
   // Background threads can call this to check if there's anything to read...
-  size_t WriteIndex() const { return write_index_; }
+  size_t WriteIndex() const { return AcquireLoad(&write_index_); }
+  void SetWriteIndex(size_t new_index) {
+    ReleaseStore(&write_index_, new_index);
+  }
 
   // The individual background threads read here (and hope that they can keep up
   // with the buffer writing).
@@ -66,6 +70,10 @@
 
  private:
   AudioFloatArray buffer_;
+
+  // |write_index_| can be accessed from several threads.  Only use
+  // the getter and setter to access it atomically.  Don't access
+  // directly!
   size_t write_index_;
 };
 
diff --git a/third_party/WebKit/Source/platform/geometry/FloatPoint.h b/third_party/WebKit/Source/platform/geometry/FloatPoint.h
index 42538c8..dbfcff0 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatPoint.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatPoint.h
@@ -133,10 +133,6 @@
 #if defined(OS_MACOSX)
   FloatPoint(const CGPoint&);
   operator CGPoint() const;
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  FloatPoint(const NSPoint&);
-  operator NSPoint() const;
-#endif
 #endif
 
   // Can we remove this one?
diff --git a/third_party/WebKit/Source/platform/geometry/FloatRect.h b/third_party/WebKit/Source/platform/geometry/FloatRect.h
index 7906580..06387c91 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatRect.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatRect.h
@@ -190,10 +190,6 @@
 #if defined(OS_MACOSX)
   FloatRect(const CGRect&);
   operator CGRect() const;
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  FloatRect(const NSRect&);
-  operator NSRect() const;
-#endif
 #endif
 
   operator SkRect() const {
diff --git a/third_party/WebKit/Source/platform/geometry/FloatSize.h b/third_party/WebKit/Source/platform/geometry/FloatSize.h
index 29b7152f..8a183d1d 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatSize.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatSize.h
@@ -120,11 +120,6 @@
   explicit FloatSize(
       const CGSize&);  // don't do this implicitly since it's lossy
   operator CGSize() const;
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  explicit FloatSize(
-      const NSSize&);  // don't do this implicitly since it's lossy
-  operator NSSize() const;
-#endif
 #endif
 
   operator SkSize() const { return SkSize::Make(width_, height_); }
diff --git a/third_party/WebKit/Source/platform/geometry/IntPoint.h b/third_party/WebKit/Source/platform/geometry/IntPoint.h
index a9091f5..f11a140 100644
--- a/third_party/WebKit/Source/platform/geometry/IntPoint.h
+++ b/third_party/WebKit/Source/platform/geometry/IntPoint.h
@@ -98,12 +98,6 @@
   explicit IntPoint(
       const CGPoint&);  // don't do this implicitly since it's lossy
   operator CGPoint() const;
-
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  explicit IntPoint(
-      const NSPoint&);  // don't do this implicitly since it's lossy
-  operator NSPoint() const;
-#endif
 #endif
 
   String ToString() const;
diff --git a/third_party/WebKit/Source/platform/geometry/IntRect.h b/third_party/WebKit/Source/platform/geometry/IntRect.h
index 7da480f..146f15a 100644
--- a/third_party/WebKit/Source/platform/geometry/IntRect.h
+++ b/third_party/WebKit/Source/platform/geometry/IntRect.h
@@ -191,9 +191,6 @@
 
 #if defined(OS_MACOSX)
   operator CGRect() const;
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  operator NSRect() const;
-#endif
 #endif
 
   operator SkRect() const;
@@ -238,13 +235,6 @@
   return a.Location() != b.Location() || a.Size() != b.Size();
 }
 
-#if defined(OS_MACOSX)
-PLATFORM_EXPORT IntRect EnclosingIntRect(const CGRect&);
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-PLATFORM_EXPORT IntRect enclosingIntRect(const NSRect&);
-#endif
-#endif
-
 // Redeclared here to avoid ODR issues.
 // See platform/testing/GeometryPrinters.h.
 void PrintTo(const IntRect&, std::ostream*);
diff --git a/third_party/WebKit/Source/platform/geometry/IntSize.h b/third_party/WebKit/Source/platform/geometry/IntSize.h
index 365bc7f..b17fa3a9 100644
--- a/third_party/WebKit/Source/platform/geometry/IntSize.h
+++ b/third_party/WebKit/Source/platform/geometry/IntSize.h
@@ -111,11 +111,6 @@
 #if defined(OS_MACOSX)
   explicit IntSize(const CGSize&);  // don't do this implicitly since it's lossy
   operator CGSize() const;
-
-#if defined(__OBJC__) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
-  explicit IntSize(const NSSize&);  // don't do this implicitly since it's lossy
-  operator NSSize() const;
-#endif
 #endif
 
   operator gfx::Size() const;
diff --git a/third_party/WebKit/Source/platform/geometry/mac/FloatPointMac.mm b/third_party/WebKit/Source/platform/geometry/mac/FloatPointMac.mm
deleted file mode 100644
index 3006cf6..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/FloatPointMac.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
- * Copyright (C) 2005 Nokia.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/FloatPoint.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-FloatPoint::FloatPoint(const NSPoint& p) : m_x(p.x), m_y(p.y) {}
-
-FloatPoint::operator NSPoint() const {
-  return NSMakePoint(m_x, m_y);
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/geometry/mac/FloatRectMac.mm b/third_party/WebKit/Source/platform/geometry/mac/FloatRectMac.mm
deleted file mode 100644
index d007eb7e..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/FloatRectMac.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
- * Copyright (C) 2005 Nokia.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/FloatRect.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-FloatRect::FloatRect(const NSRect& r) : m_location(r.origin), m_size(r.size) {}
-
-FloatRect::operator NSRect() const {
-  return NSMakeRect(x(), y(), width(), height());
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/geometry/mac/FloatSizeMac.mm b/third_party/WebKit/Source/platform/geometry/mac/FloatSizeMac.mm
deleted file mode 100644
index 5f33b714..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/FloatSizeMac.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
- * Copyright (C) 2005 Nokia.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/FloatSize.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-FloatSize::FloatSize(const NSSize& s) : m_width(s.width), m_height(s.height) {}
-
-FloatSize::operator NSSize() const {
-  return NSMakeSize(m_width, m_height);
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/geometry/mac/IntPointMac.mm b/third_party/WebKit/Source/platform/geometry/mac/IntPointMac.mm
deleted file mode 100644
index 94acbe1..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/IntPointMac.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/IntPoint.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-IntPoint::IntPoint(const NSPoint& p)
-    : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y)) {}
-
-IntPoint::operator NSPoint() const {
-  return NSMakePoint(m_x, m_y);
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/geometry/mac/IntRectMac.mm b/third_party/WebKit/Source/platform/geometry/mac/IntRectMac.mm
deleted file mode 100644
index 81adf86..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/IntRectMac.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2003, 2006 Apple Computer, 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/IntRect.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-IntRect::operator NSRect() const {
-  return NSMakeRect(x(), y(), width(), height());
-}
-
-IntRect enclosingIntRect(const NSRect& rect) {
-  int l = static_cast<int>(floorf(rect.origin.x));
-  int t = static_cast<int>(floorf(rect.origin.y));
-  int r = static_cast<int>(ceilf(NSMaxX(rect)));
-  int b = static_cast<int>(ceilf(NSMaxY(rect)));
-  return IntRect(l, t, r - l, b - t);
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/geometry/mac/IntSizeMac.mm b/third_party/WebKit/Source/platform/geometry/mac/IntSizeMac.mm
deleted file mode 100644
index 52b7c645..0000000
--- a/third_party/WebKit/Source/platform/geometry/mac/IntSizeMac.mm
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
- */
-
-#include "platform/geometry/IntSize.h"
-
-namespace blink {
-
-#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
-
-IntSize::IntSize(const NSSize& s)
-    : m_width(static_cast<int>(s.width)),
-      m_height(static_cast<int>(s.height)) {}
-
-IntSize::operator NSSize() const {
-  return NSMakeSize(m_width, m_height);
-}
-
-#endif
-}
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
index 5d34b39..b1238d5 100644
--- a/third_party/WebKit/Source/platform/graphics/Gradient.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
@@ -167,8 +167,7 @@
 }
 
 void Gradient::ApplyToFlags(PaintFlags& flags, const SkMatrix& local_matrix) {
-  if (!cached_shader_ ||
-      local_matrix != cached_shader_->sk_shader()->getLocalMatrix() ||
+  if (!cached_shader_ || local_matrix != cached_shader_->GetLocalMatrix() ||
       flags.getColorFilter() != color_filter_.get()) {
     color_filter_ = flags.refColorFilter();
     flags.setColorFilter(nullptr);
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
index bb44542..5e84d5e7 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -177,8 +177,11 @@
   int ScrollSize(ScrollbarOrientation) const override { return 100; }
   bool IsScrollCornerVisible() const override { return false; }
   IntRect ScrollCornerRect() const override { return IntRect(); }
-  int VisibleWidth() const override { return 10; }
-  int VisibleHeight() const override { return 10; }
+  IntRect VisibleContentRect(
+      IncludeScrollbarsInRect = kExcludeScrollbars) const override {
+    return IntRect(ScrollOffsetInt().Width(), ScrollOffsetInt().Height(), 10,
+                   10);
+  }
   IntSize ContentsSize() const override { return IntSize(100, 100); }
   bool ScrollbarsCanBeActive() const override { return false; }
   IntRect ScrollableAreaBoundingBox() const override { return IntRect(); }
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
index 181339a..2e65de1 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
@@ -63,7 +63,7 @@
 }
 
 bool Pattern::IsLocalMatrixChanged(const SkMatrix& local_matrix) const {
-  return local_matrix != cached_shader_->sk_shader()->getLocalMatrix();
+  return local_matrix != cached_shader_->GetLocalMatrix();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.cpp b/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.cpp
index ab57e09..3e221b5 100644
--- a/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.cpp
@@ -10,6 +10,7 @@
 #include "platform/graphics/gpu/SharedGpuContext.h"
 #include "public/platform/Platform.h"
 #include "skia/ext/texture_handle.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 
 namespace blink {
@@ -47,16 +48,10 @@
   GrGLTextureInfo texture_info;
   texture_info.fTarget = GL_TEXTURE_2D;
   texture_info.fID = shared_context_texture_id;
-  GrBackendTextureDesc backend_texture;
-  backend_texture.fOrigin = kBottomLeft_GrSurfaceOrigin;
-  backend_texture.fWidth = mailbox_size.Width();
-  backend_texture.fHeight = mailbox_size.Height();
-  backend_texture.fConfig = kSkia8888_GrPixelConfig;
-  backend_texture.fTextureHandle =
-      skia::GrGLTextureInfoToGrBackendObject(texture_info);
-
-  sk_sp<SkImage> new_image =
-      SkImage::MakeFromAdoptedTexture(shared_gr_context, backend_texture);
+  GrBackendTexture backend_texture(mailbox_size.Width(), mailbox_size.Height(),
+                                   kSkia8888_GrPixelConfig, texture_info);
+  sk_sp<SkImage> new_image = SkImage::MakeFromAdoptedTexture(
+      shared_gr_context, backend_texture, kBottomLeft_GrSurfaceOrigin);
   ReleaseImageThreadSafe();
   image_ = new_image;
   shared_context_id_ = SharedGpuContext::ContextId();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
index fa3815f7..1973a9f 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -609,20 +609,6 @@
   }
 }
 
-IntRect ScrollableArea::VisibleContentRect(
-    IncludeScrollbarsInRect scrollbar_inclusion) const {
-  int scrollbar_width =
-      scrollbar_inclusion == kIncludeScrollbars ? VerticalScrollbarWidth() : 0;
-  int scrollbar_height = scrollbar_inclusion == kIncludeScrollbars
-                             ? HorizontalScrollbarHeight()
-                             : 0;
-
-  return EnclosingIntRect(
-      IntRect(GetScrollOffset().Width(), GetScrollOffset().Height(),
-              std::max(0, VisibleWidth() + scrollbar_width),
-              std::max(0, VisibleHeight() + scrollbar_height)));
-}
-
 IntSize ScrollableArea::ClampScrollOffset(const IntSize& scroll_offset) const {
   return scroll_offset.ShrunkTo(MaximumScrollOffsetInt())
       .ExpandedTo(MinimumScrollOffsetInt());
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
index 1878aed0..a7a8c93 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -240,7 +240,7 @@
   }
 
   virtual IntRect VisibleContentRect(
-      IncludeScrollbarsInRect = kExcludeScrollbars) const;
+      IncludeScrollbarsInRect = kExcludeScrollbars) const = 0;
   virtual int VisibleHeight() const { return VisibleContentRect().Height(); }
   virtual int VisibleWidth() const { return VisibleContentRect().Width(); }
   virtual IntSize ContentsSize() const = 0;
diff --git a/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp b/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp
index 10ec3a8..8d9ebf3 100644
--- a/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ScrollMetricsTest.cpp
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ClientRect.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/WebLocalFrameBase.h"
+#include "core/geometry/DOMRect.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutView.h"
 #include "core/paint/PaintLayerScrollableArea.h"
@@ -101,7 +101,7 @@
                                const WebGestureDevice device) {
   DCHECK(element);
   DCHECK(element->getBoundingClientRect());
-  ClientRect* rect = element->getBoundingClientRect();
+  DOMRect* rect = element->getBoundingClientRect();
   ScrollBeginEventBuilder scroll_begin(
       IntPoint(rect->left() + rect->width() / 2,
                rect->top() + rect->height() / 2),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
index 7867317..3da9d15 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -285,7 +285,6 @@
     def _test_is_expected_missing(self, test_file):
         expectations = self._expectations.model().get_expectations(test_file)
         return (test_expectations.MISSING in expectations or
-                test_expectations.NEEDS_REBASELINE in expectations or
                 test_expectations.NEEDS_MANUAL_REBASELINE in expectations)
 
     def _test_is_slow(self, test_file):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py
index 1edcba9fd..e3b5857 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py
@@ -145,7 +145,22 @@
         """
         fs = self._filesystem
         output_filename = fs.join(self._root_output_dir, self._test_name)
-        return fs.splitext(output_filename)[0] + modifier
+        base, extension = fs.splitext(output_filename)
+
+        # Below is an affordance for WPT test files that become multiple tests using different URL params,
+        # For example,
+        # - html/syntax/parsing/html5lib_adoption01.html
+        # Becomes two tests:
+        # - html/syntax/parsing/html5lib_adoption01.html?run_type=write
+        # - html/syntax/parsing/html5lib_adoption01.html?run_type=uri
+        # But previously their result file would be the same, since everything after the extension
+        # is removed. Instead, for files with URL params, we use the whole filename for writing results.
+        if '?' in extension:
+            # Question marks are reserved characters in Windows filenames.
+            sanitized_filename = output_filename.replace('?', '_')
+            return sanitized_filename + modifier
+
+        return base + modifier
 
     def _write_file(self, path, contents):
         if contents is not None:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/generate_results_dashboard.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/generate_results_dashboard.py
deleted file mode 100644
index 2fd2402..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/generate_results_dashboard.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# Copyright (C) 2014 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.
-
-import json
-
-
-class ProcessJsonData(object):
-
-    def __init__(self, current_result_json_dict, old_failing_results_list, old_full_results_list):
-        self._current_result_json_dict = current_result_json_dict
-        self._old_failing_results_list = old_failing_results_list
-        self._old_full_results_list = old_full_results_list
-        self._final_result = []
-
-    def _get_test_result(self, test_result_data):
-        actual = test_result_data['actual']
-        expected = test_result_data['expected']
-        if actual == 'SKIP':
-            return actual
-        if actual == expected:
-            return 'HASSTDERR' if test_result_data.get('has_stderr') == 'true' else 'PASS'
-        else:
-            return actual
-
-    def _recurse_json_object(self, json_object, key_list):
-        for key in key_list:
-            try:
-                json_object = json_object[key]
-            except KeyError:
-                return 'NOTFOUND'
-        return self._get_test_result(json_object)
-
-    def _process_previous_json_results(self, key_list):
-        row = []
-        length = len(self._old_failing_results_list)
-        for index in range(0, length):
-            result = self._recurse_json_object(self._old_failing_results_list[index]['tests'], key_list)
-            if result == 'NOTFOUND':
-                result = self._recurse_json_object(self._old_full_results_list[index]['tests'], key_list)
-            row.append(result)
-        return row
-
-    def _add_archived_result(self, json_object, result):
-        json_object['archived_results'] = result
-
-    def _process_json_object(self, json_object, keyList):
-        for key, subdict in json_object.iteritems():
-            if isinstance(subdict, dict):
-                self._process_json_object(subdict, keyList + [key])
-            else:
-                row = [self._get_test_result(json_object)]
-                row += self._process_previous_json_results(keyList)
-                json_object.clear()
-                self._add_archived_result(json_object, row)
-                return
-
-    def generate_archived_result(self):
-        for key in self._current_result_json_dict['tests']:
-            self._process_json_object(self._current_result_json_dict['tests'][key], [key])
-        return self._current_result_json_dict
-
-
-class DashBoardGenerator(object):
-
-    def __init__(self, port):
-        self._port = port
-        self._filesystem = port.host.filesystem
-        self._results_directory = self._port.results_directory()
-        self._results_directory_path = self._filesystem.dirname(self._results_directory)
-        self._current_result_json_dict = {}
-        self._old_failing_results_list = []
-        self._old_full_results_list = []
-        self._final_result = []
-
-    def _add_individual_result_links(self, results_directories):
-        archived_results_file_list = [(file + '/results.html') for file in results_directories]
-        archived_results_file_list.insert(0, 'results.html')
-        self._current_result_json_dict['result_links'] = archived_results_file_list
-
-    def _copy_dashboard_html(self):
-        dashboard_file = self._filesystem.join(self._results_directory, 'dashboard.html')
-        dashboard_html_file_path = self._filesystem.join(
-            self._port.layout_tests_dir(), 'fast/harness/archived-results-dashboard.html')
-        if not self._filesystem.exists(dashboard_file):
-            if self._filesystem.exists(dashboard_html_file_path):
-                self._filesystem.copyfile(dashboard_html_file_path, dashboard_file)
-
-    def _initialize(self):
-        file_list = self._filesystem.listdir(self._results_directory_path)
-        results_directories = []
-        for dir in file_list:
-            full_dir_path = self._filesystem.join(self._results_directory_path, dir)
-            if self._filesystem.isdir(full_dir_path):
-                if self._results_directory in full_dir_path:
-                    results_directories.append(full_dir_path)
-        results_directories.sort(reverse=True, key=lambda x: self._filesystem.mtime(x))
-        current_failing_results_json_file = self._filesystem.join(results_directories[0], 'failing_results.json')
-        input_json_string = self._filesystem.read_text_file(current_failing_results_json_file)
-        input_json_string = input_json_string[12:-2]   # Remove preceding string ADD_RESULTS( and ); at the end
-        self._current_result_json_dict['tests'] = json.loads(input_json_string)['tests']
-        results_directories = results_directories[1:]
-
-        # To add hyperlink to individual results.html
-        self._add_individual_result_links(results_directories)
-
-        # Load the remaining stale layout test results Json's to create the dashboard
-        for json_file in results_directories:
-            failing_json_file_path = self._filesystem.join(json_file, 'failing_results.json')
-            full_json_file_path = self._filesystem.join(json_file, 'full_results.json')
-            json_string = self._filesystem.read_text_file(failing_json_file_path)
-            json_string = json_string[12:-2]   # Remove preceding string ADD_RESULTS( and ); at the end
-            self._old_failing_results_list.append(json.loads(json_string))
-            json_string_full_result = self._filesystem.read_text_file(full_json_file_path)
-            self._old_full_results_list.append(json.loads(json_string_full_result))
-        self._copy_dashboard_html()
-
-    def generate(self):
-        self._initialize()
-
-        # There must be at least one archived result to be processed
-        if self._current_result_json_dict:
-            process_json_data = ProcessJsonData(self._current_result_json_dict,
-                                                self._old_failing_results_list, self._old_full_results_list)
-            self._final_result = process_json_data.generate_archived_result()
-            final_json = json.dumps(self._final_result)
-            final_json = 'ADD_RESULTS(' + final_json + ');'
-            archived_results_file_path = self._filesystem.join(self._results_directory, 'archived_results.json')
-            self._filesystem.write_text_file(archived_results_file_path, final_json)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
index ca7dfe1..c357dfd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations.py
@@ -35,6 +35,7 @@
 from webkitpy.common import exit_codes
 from webkitpy.layout_tests.models import test_expectations
 from webkitpy.layout_tests.port.factory import platform_options
+from webkitpy.w3c.wpt_manifest import WPTManifest
 
 _log = logging.getLogger(__name__)
 
@@ -151,6 +152,11 @@
     else:
         host = Host()
 
+    # Need to generate MANIFEST.json since some expectations correspond to WPT
+    # tests that aren't files and only exist in the manifest.
+    _log.info('Generating MANIFEST.json for web-platform-tests ...')
+    WPTManifest.ensure_manifest(host)
+
     try:
         exit_status = run_checks(host, options, stderr)
     except KeyboardInterrupt:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
index cf224c2a..14efcd2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/lint_test_expectations_unittest.py
@@ -118,12 +118,7 @@
         logger, handler = lint_test_expectations.set_up_logging(logging_stream)
         try:
             res = lint_test_expectations.lint(host, options)
-            self.assertEqual(
-                res,
-                ['/test.checkout/LayoutTests/TestExpectations: '
-                 '/test.checkout/LayoutTests/TestExpectations:5 '
-                 'NeedsRebaseline is deprecated; see https://crbug.com/692811 '
-                 'failures/expected/needsrebaseline.html'])
+            self.assertEqual(res, [])
         finally:
             lint_test_expectations.tear_down_logging(logger, handler)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results_unittest.py
index 9e95452..89b8912 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/merge_results_unittest.py
@@ -543,12 +543,6 @@
 
 class LayoutTestDirMergerTests(unittest.TestCase):
 
-    maxDiff = None
-
-    # Common HTML files every shard has.
-    dashboard_html = '<html><body>Dashboard would be here.</body></html>'
-    dashboard_css = '.css { value = would be here }'
-
     # JSON files for shard 1
     # Shard1 has the following tests;
     #   testdir1/test1.html
@@ -784,8 +778,6 @@
         # Files for shard0
         '/shards/0/layout-test-results/access_log.txt': shard0_access_log,
         '/shards/0/layout-test-results/archived_results.json': shard0_archived_results_json,
-        '/shards/0/layout-test-results/dashboard.css': dashboard_css,
-        '/shards/0/layout-test-results/dashboard.html': dashboard_html,
         '/shards/0/layout-test-results/error_log.txt': shard0_error_log,
         '/shards/0/layout-test-results/failing_results.json': "ADD_RESULTS(" + shard0_output_json + ");",
         '/shards/0/layout-test-results/full_results.json': shard0_output_json,
@@ -810,8 +802,6 @@
         # Files for shard1
         '/shards/1/layout-test-results/access_log.txt': shard1_access_log,
         '/shards/1/layout-test-results/archived_results.json': shard1_archived_results_json,
-        '/shards/1/layout-test-results/dashboard.css': dashboard_css,
-        '/shards/1/layout-test-results/dashboard.html': dashboard_html,
         '/shards/1/layout-test-results/error_log.txt': shard1_error_log,
         '/shards/1/layout-test-results/failing_results.json': "ADD_RESULTS(" + shard1_output_json + ");",
         '/shards/1/layout-test-results/full_results.json': shard1_output_json,
@@ -1024,8 +1014,6 @@
     layout_test_output_filesystem = {
         '/out/layout-test-results/access_log.txt': output_access_log,
         '/out/layout-test-results/archived_results.json': output_archived_results_json,
-        '/out/layout-test-results/dashboard.css': dashboard_css,
-        '/out/layout-test-results/dashboard.html': dashboard_html,
         '/out/layout-test-results/error_log.txt': output_error_log,
         '/out/layout-test-results/failing_results.json': "ADD_RESULTS(" + output_output_json + ");",
         '/out/layout-test-results/full_results.json': output_output_json,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
index 8422d6e9..3698ce3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -44,7 +44,7 @@
 # FIXME: range() starts with 0 which makes if expectation checks harder
 # as PASS is 0.
 (PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, LEAK, SKIP, WONTFIX,
- SLOW, REBASELINE, NEEDS_REBASELINE, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NOW, NONE) = range(19)
+ SLOW, REBASELINE, NEEDS_REBASELINE_UNUSED, NEEDS_MANUAL_REBASELINE, MISSING, FLAKY, NOW, NONE) = range(19)
 
 # FIXME: Perhaps these two routines should be part of the Port instead?
 BASELINE_SUFFIX_LIST = ('png', 'wav', 'txt')
@@ -56,7 +56,6 @@
 NAMED_BUG_PREFIX = 'Bug('
 
 MISSING_KEYWORD = 'Missing'
-NEEDS_REBASELINE_KEYWORD = 'NeedsRebaseline'
 NEEDS_MANUAL_REBASELINE_KEYWORD = 'NeedsManualRebaseline'
 
 
@@ -79,7 +78,6 @@
     # FIXME: Rename these to *_KEYWORD as in MISSING_KEYWORD above, but make
     # the case studdly-caps to match the actual file contents.
     REBASELINE_MODIFIER = 'rebaseline'
-    NEEDS_REBASELINE_MODIFIER = 'needsrebaseline'
     NEEDS_MANUAL_REBASELINE_MODIFIER = 'needsmanualrebaseline'
     PASS_EXPECTATION = 'pass'
     SKIP_MODIFIER = 'skip'
@@ -170,20 +168,16 @@
         if self.REBASELINE_MODIFIER in expectations:
             expectation_line.warnings.append('REBASELINE should only be used for running rebaseline.py. Cannot be checked in.')
 
-        if self.NEEDS_REBASELINE_MODIFIER in expectations:
-            expectation_line.warnings.append('NeedsRebaseline is deprecated; see https://crbug.com/692811')
-
-        if self.NEEDS_REBASELINE_MODIFIER in expectations or self.NEEDS_MANUAL_REBASELINE_MODIFIER in expectations:
+        if self.NEEDS_MANUAL_REBASELINE_MODIFIER in expectations:
             for test in expectation_line.matching_tests:
                 if self._port.reference_files(test):
                     text_expected_filename = self._port.expected_filename(test, '.txt')
                     if not self._port.host.filesystem.exists(text_expected_filename):
                         expectation_line.warnings.append(
-                            'A reftest without text expectation cannot be marked as NeedsRebaseline/NeedsManualRebaseline')
+                            'A reftest without text expectation cannot be marked as NeedsManualRebaseline')
 
         specifiers = [specifier.lower() for specifier in expectation_line.specifiers]
-        if (self.REBASELINE_MODIFIER in expectations or self.NEEDS_REBASELINE_MODIFIER in expectations) and (
-                'debug' in specifiers or 'release' in specifiers):
+        if self.REBASELINE_MODIFIER in expectations and ('debug' in specifiers or 'release' in specifiers):
             expectation_line.warnings.append('A test cannot be rebaselined for Debug/Release.')
 
     def _parse_expectations(self, expectation_line):
@@ -303,7 +297,6 @@
         MISSING_KEYWORD: 'MISSING',
         'Pass': 'PASS',
         'Rebaseline': 'REBASELINE',
-        NEEDS_REBASELINE_KEYWORD: 'NEEDSREBASELINE',
         NEEDS_MANUAL_REBASELINE_KEYWORD: 'NEEDSMANUALREBASELINE',
         'Skip': 'SKIP',
         'Slow': 'SLOW',
@@ -445,8 +438,8 @@
 
         if 'MISSING' in expectations:
             warnings.append(
-                '"Missing" expectations are not allowed; either download new baselines '
-                '(see https://goo.gl/SHVYrZ) or use "NeedsRebaseline" expectations.')
+                '"Missing" expectations are not allowed; download new baselines '
+                '(see https://goo.gl/SHVYrZ), or as a fallback, use "NeedsManualRebaseline".')
 
         expectation_line.bugs = bugs
         expectation_line.specifiers = specifiers
@@ -885,7 +878,6 @@
         'leak': LEAK,
         'missing': MISSING,
         TestExpectationParser.SKIP_MODIFIER: SKIP,
-        TestExpectationParser.NEEDS_REBASELINE_MODIFIER: NEEDS_REBASELINE,
         TestExpectationParser.NEEDS_MANUAL_REBASELINE_MODIFIER: NEEDS_MANUAL_REBASELINE,
         TestExpectationParser.WONTFIX_MODIFIER: WONTFIX,
         TestExpectationParser.SLOW_MODIFIER: SLOW,
@@ -943,10 +935,9 @@
 
         if result in expected_results:
             return True
-        if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and (
-                NEEDS_REBASELINE in expected_results or NEEDS_MANUAL_REBASELINE in expected_results):
+        if result in (PASS, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, MISSING) and NEEDS_MANUAL_REBASELINE in expected_results:
             return True
-        if result in (TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_results):
+        if result in (TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO) and FAIL in expected_results:
             return True
         if result == MISSING and test_needs_rebaselining:
             return True
@@ -1060,9 +1051,6 @@
     def expectations(self):
         return self._expectations
 
-    def get_needs_rebaseline_failures(self):
-        return self._model.get_test_set(NEEDS_REBASELINE)
-
     def get_rebaselining_failures(self):
         return self._model.get_test_set(REBASELINE)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
index 5569e757..f7a71d2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
@@ -35,7 +35,7 @@
 from webkitpy.layout_tests.models.test_expectations import (
     TestExpectationLine, TestExpectations, ParseError, TestExpectationParser,
     PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO,
-    TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, NEEDS_REBASELINE, MISSING
+    TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, NEEDS_MANUAL_REBASELINE, MISSING
 )
 
 
@@ -53,13 +53,10 @@
         return ['failures/expected/text.html',
                 'failures/expected/image_checksum.html',
                 'failures/expected/crash.html',
-                'failures/expected/needsrebaseline.html',
                 'failures/expected/needsmanualrebaseline.html',
                 'failures/expected/image.html',
                 'failures/expected/timeout.html',
                 'passes/text.html',
-                'reftests/failures/expected/needsrebaseline.html',
-                'reftests/failures/expected/needsrebaseline_with_txt.html',
                 'reftests/failures/expected/needsmanualrebaseline.html',
                 'reftests/failures/expected/needsmanualrebaseline_with_txt.html',
                 'reftests/failures/expected/has_unused_expectation.html']
@@ -68,7 +65,6 @@
         return """
 Bug(test) failures/expected/text.html [ Failure ]
 Bug(test) failures/expected/crash.html [ Crash ]
-Bug(test) failures/expected/needsrebaseline.html [ NeedsRebaseline ]
 Bug(test) failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]
 Bug(test) failures/expected/image_checksum.html [ Crash ]
 Bug(test) failures/expected/image.html [ Crash Mac ]
@@ -139,16 +135,24 @@
         self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True), True)
         self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False), False)
 
-        self.assertTrue(TestExpectations.result_was_expected(PASS, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(MISSING, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(TEXT, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(IMAGE, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(IMAGE_PLUS_TEXT,
-                                                             set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertTrue(TestExpectations.result_was_expected(AUDIO, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(TIMEOUT, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(CRASH, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
-        self.assertFalse(TestExpectations.result_was_expected(LEAK, set([NEEDS_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            PASS, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            MISSING, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            TEXT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            IMAGE, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            IMAGE_PLUS_TEXT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertTrue(TestExpectations.result_was_expected(
+            AUDIO, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertFalse(TestExpectations.result_was_expected(
+            TIMEOUT, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertFalse(TestExpectations.result_was_expected(
+            CRASH, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
+        self.assertFalse(TestExpectations.result_was_expected(
+            LEAK, set([NEEDS_MANUAL_REBASELINE]), test_needs_rebaselining=False))
 
     def test_remove_pixel_failures(self):
         self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL]))
@@ -197,31 +201,6 @@
             filesystem.write_text_file(
                 filesystem.join(
                     self._port.layout_tests_dir(),
-                    'reftests/failures/expected/needsrebaseline.html'),
-                'content')
-            filesystem.write_text_file(
-                filesystem.join(
-                    self._port.layout_tests_dir(),
-                    'reftests/failures/expected/needsrebaseline-expected.html'),
-                'content')
-            filesystem.write_text_file(
-                filesystem.join(
-                    self._port.layout_tests_dir(),
-                    'reftests/failures/expected/needsrebaseline_with_txt.html'),
-                'content')
-            filesystem.write_text_file(
-                filesystem.join(
-                    self._port.layout_tests_dir(),
-                    'reftests/failures/expected/needsrebaseline_with_txt-expected.html'),
-                'content')
-            filesystem.write_text_file(
-                filesystem.join(
-                    self._port.layout_tests_dir(),
-                    'reftests/failures/expected/needsrebaseline_with_txt-expected.txt'),
-                'content')
-            filesystem.write_text_file(
-                filesystem.join(
-                    self._port.layout_tests_dir(),
                     'reftests/failures/expected/needsmanualrebaseline.html'),
                 'content')
             filesystem.write_text_file(
@@ -249,21 +228,14 @@
                     self._port.layout_tests_dir(),
                     'reftests/failures/expected/needsmanualrebaseline_with_txt-expected.txt'),
                 'content')
-            self.parse_exp("""Bug(user) reftests/failures/expected/needsrebaseline.html [ NeedsRebaseline ]
-Bug(user) reftests/failures/expected/needsrebaseline_with_txt.html [ NeedsRebaseline ]
-Bug(user) reftests/failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]
-Bug(user) reftests/failures/expected/needsmanualrebaseline_with_txt.html [ NeedsManualRebaseline ]
-""", is_lint_mode=True)
+            self.parse_exp(
+                'Bug(user) reftests/failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]\n'
+                'Bug(user) reftests/failures/expected/needsmanualrebaseline_with_txt.html [ NeedsManualRebaseline ]\n',
+                is_lint_mode=True)
             self.assertFalse(True, "ParseError wasn't raised")
         except ParseError as error:
-            warnings = ('expectations:1 NeedsRebaseline is deprecated; see https://crbug.com/692811 '
-                        'reftests/failures/expected/needsrebaseline.html\n'
-                        'expectations:1 A reftest without text expectation cannot be marked as '
-                        'NeedsRebaseline/NeedsManualRebaseline reftests/failures/expected/needsrebaseline.html\n'
-                        'expectations:2 NeedsRebaseline is deprecated; see https://crbug.com/692811 '
-                        'reftests/failures/expected/needsrebaseline_with_txt.html\n'
-                        'expectations:3 A reftest without text expectation cannot be marked as '
-                        'NeedsRebaseline/NeedsManualRebaseline reftests/failures/expected/needsmanualrebaseline.html')
+            warnings = ('expectations:1 A reftest without text expectation cannot be marked as '
+                        'NeedsManualRebaseline reftests/failures/expected/needsmanualrebaseline.html')
             self.assertEqual(str(error), warnings)
 
     def test_parse_warning(self):
@@ -273,14 +245,12 @@
             filesystem.write_text_file(filesystem.join(self._port.layout_tests_dir(), 'test-to-rebaseline.html'), 'content')
             self.parse_exp('Bug(user) [ FOO ] failures/expected/text.html [ Failure ]\n'
                            'Bug(user) non-existent-test.html [ Failure ]\n'
-                           'Bug(user) disabled-test.html-disabled [ Failure ]\n'
-                           'Bug(user) [ Release ] test-to-rebaseline.html [ NeedsRebaseline ]', is_lint_mode=True)
+                           'Bug(user) disabled-test.html-disabled [ Failure ]\n',
+                           is_lint_mode=True)
             self.assertFalse(True, "ParseError wasn't raised")
         except ParseError as error:
             warnings = ('expectations:1 Unrecognized specifier "FOO" failures/expected/text.html\n'
-                        'expectations:2 Path does not exist. non-existent-test.html\n'
-                        'expectations:4 NeedsRebaseline is deprecated; see https://crbug.com/692811 test-to-rebaseline.html\n'
-                        'expectations:4 A test cannot be rebaselined for Debug/Release. test-to-rebaseline.html')
+                        'expectations:2 Path does not exist. non-existent-test.html')
             self.assertEqual(str(error), warnings)
 
     def test_parse_warnings_are_logged_if_not_in_lint_mode(self):
@@ -337,8 +307,6 @@
         self.assertFalse(match('failures/expected/image_checksum.html', PASS, True))
         self.assertFalse(match('failures/expected/image_checksum.html', PASS, False))
         self.assertFalse(match('failures/expected/crash.html', PASS, False))
-        self.assertTrue(match('failures/expected/needsrebaseline.html', TEXT, True))
-        self.assertFalse(match('failures/expected/needsrebaseline.html', CRASH, True))
         self.assertTrue(match('failures/expected/needsmanualrebaseline.html', TEXT, True))
         self.assertFalse(match('failures/expected/needsmanualrebaseline.html', CRASH, True))
         self.assertTrue(match('passes/text.html', PASS, False))
@@ -662,22 +630,24 @@
 Bug(y) [ Win Mac Debug ] failures/expected/foo.html [ Crash ]
 """, actual_expectations)
 
-    def test_remove_needs_rebaseline(self):
+    def test_remove_needs_manual_rebaseline(self):
         host = MockHost()
         test_port = host.port_factory.get('test-win-win7', None)
         test_port.test_exists = lambda test: True
         test_port.test_isfile = lambda test: True
 
         test_config = test_port.test_configuration()
-        test_port.expectations_dict = lambda: {'expectations': """Bug(x) [ Win ] failures/expected/foo.html [ NeedsRebaseline ]
-"""}
+        test_port.expectations_dict = lambda: {
+            'expectations': 'Bug(x) [ Win ] failures/expected/foo.html [ NeedsManualRebaseline ]\n'
+        }
         expectations = TestExpectations(test_port, self.get_basic_tests())
 
         actual_expectations = expectations.remove_configurations([('failures/expected/foo.html', test_config)])
 
-        self.assertEqual("""Bug(x) [ Win7 Debug ] failures/expected/foo.html [ NeedsRebaseline ]
-Bug(x) [ Win10 ] failures/expected/foo.html [ NeedsRebaseline ]
-""", actual_expectations)
+        self.assertEqual(
+            'Bug(x) [ Win7 Debug ] failures/expected/foo.html [ NeedsManualRebaseline ]\n'
+            'Bug(x) [ Win10 ] failures/expected/foo.html [ NeedsManualRebaseline ]\n',
+            actual_expectations)
 
     def test_remove_multiple_configurations(self):
         host = MockHost()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
index 1c9815f..342a196 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
@@ -204,7 +204,6 @@
                 'MISSING': 0,
                 'TEXT': 1,
                 'IMAGE': 1,
-                'NEEDSREBASELINE': 0,
                 'NEEDSMANUALREBASELINE': 0,
                 'PASS': 0,
                 'REBASELINE': 0,
@@ -226,7 +225,6 @@
                 'MISSING': 0,
                 'TEXT': 0,
                 'IMAGE': 0,
-                'NEEDSREBASELINE': 0,
                 'NEEDSMANUALREBASELINE': 0,
                 'PASS': 1,
                 'REBASELINE': 0,
@@ -248,7 +246,6 @@
                 'MISSING': 0,
                 'TEXT': 0,
                 'IMAGE': 0,
-                'NEEDSREBASELINE': 0,
                 'NEEDSMANUALREBASELINE': 0,
                 'PASS': 5,
                 'REBASELINE': 0,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 07d747ac..e3fd153d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -34,7 +34,6 @@
 
 import collections
 import errno
-import functools
 import json
 import logging
 import optparse
@@ -659,22 +658,43 @@
         return reftest_list
 
     def tests(self, paths):
-        """Returns the list of tests found matching paths."""
+        """Returns all tests or tests matching supplied paths.
+
+        Args:
+            paths: Array of paths to match. If supplied, this function will only
+                return tests matching at least one path in paths.
+
+        Returns:
+            An array of test paths and test names. The latter are web platform
+            tests that don't correspond to file paths but are valid tests,
+            for instance a file path test.any.js could correspond to two test
+            names: test.any.html and test.any.worker.html.
+        """
         tests = self.real_tests(paths)
 
         suites = self.virtual_test_suites()
         if paths:
             tests.extend(self._virtual_tests_matching_paths(paths, suites))
+            tests.extend(self._wpt_test_urls_matching_paths(paths))
         else:
             tests.extend(self._all_virtual_tests(suites))
+            tests.extend(['external/wpt' + test for test in self._wpt_manifest().all_urls()])
+
         return tests
 
     def real_tests(self, paths):
         # When collecting test cases, skip these directories.
-        skipped_directories = set(['platform', 'resources', 'support', 'script-tests', 'reference', 'reftest'])
-        files = find_files.find(self._filesystem, self.layout_tests_dir(), paths,
-                                skipped_directories, functools.partial(Port.is_test_file, self), self.test_key)
-        return self._convert_wpt_file_paths_to_url_paths([self.relative_test_filename(f) for f in files])
+        skipped_directories = set([
+            'platform', 'resources', 'support', 'script-tests',
+            'reference', 'reftest', 'external'
+        ])
+        is_non_wpt_real_test_file = lambda fs, dirname, filename: (
+            self.is_test_file(fs, dirname, filename)
+            and not re.search(r'[/\\]external[/\\]wpt([/\\].*)?$', dirname)
+        )
+        files = find_files.find(self._filesystem, self.layout_tests_dir(), paths, skipped_directories,
+                                is_non_wpt_real_test_file, self.test_key)
+        return [self.relative_test_filename(f) for f in files]
 
     @staticmethod
     # If any changes are made here be sure to update the isUsedInReftest method in old-run-webkit-tests as well.
@@ -714,17 +734,15 @@
         return Port._has_supported_extension(
             filesystem, filename) and not Port.is_reference_html_file(filesystem, dirname, filename)
 
-    def _convert_wpt_file_paths_to_url_paths(self, files):
+    def _convert_wpt_file_path_to_url_paths(self, file_path):
         tests = []
-        for file_path in files:
-            # Path separators are normalized by relative_test_filename().
-            match = re.search(r'external/wpt/(.*)$', file_path)
-            if not match:
-                tests.append(file_path)
-                continue
-            urls = self._wpt_manifest().file_path_to_url_paths(match.group(1))
-            for url in urls:
-                tests.append(file_path[0:match.start(1)] + url)
+        # Path separators are normalized by relative_test_filename().
+        match = re.search(r'external/wpt/(.*)$', file_path)
+        if not match:
+            return [file_path]
+        urls = self._wpt_manifest().file_path_to_url_paths(match.group(1))
+        for url in urls:
+            tests.append(file_path[0:match.start(1)] + url)
         return tests
 
     @memoized
@@ -820,7 +838,7 @@
         """Returns True if the test name refers to an existing test or baseline."""
         # Used by test_expectations.py to determine if an entry refers to a
         # valid test and by printing.py to determine if baselines exist.
-        return self.test_isfile(test_name) or self.test_isdir(test_name)
+        return self.is_wpt_test(test_name) or self.test_isfile(test_name) or self.test_isdir(test_name)
 
     def split_test(self, test_name):
         """Splits a test name into the 'directory' part and the 'basename' part."""
@@ -1506,9 +1524,42 @@
                     tests.append(test)
         return tests
 
+    def _wpt_test_urls_matching_paths(self, paths):
+        tests = []
+
+        for test_url_path in self._wpt_manifest().all_urls():
+            if test_url_path[0] == '/':
+                test_url_path = test_url_path[1:]
+
+            full_test_url_path = 'external/wpt/' + test_url_path
+
+            for path in paths:
+                if 'external' not in path:
+                    continue
+
+                wpt_path = path.replace('external/wpt/', '')
+
+                # When `test_url_path` is test.any.html or test.any.worker.html and path is test.any.js
+                matches_any_js_test = (
+                    self._wpt_manifest().is_test_file(wpt_path)
+                    and test_url_path.startswith(re.sub(r'\.js$', '', wpt_path))
+                )
+
+                # Get a list of directories for both paths, filter empty strings
+                full_test_url_directories = filter(None, full_test_url_path.split(self._filesystem.sep))
+                path_directories = filter(None, path.split(self._filesystem.sep))
+
+                # For all other path matches within WPT
+                if matches_any_js_test or path_directories == full_test_url_directories[0:len(path_directories)]:
+                    wpt_file_paths = self._convert_wpt_file_path_to_url_paths(test_url_path)
+                    tests.extend('external/wpt/' + wpt_file_path for wpt_file_path in wpt_file_paths)
+
+        return tests
+
     def _populate_virtual_suite(self, suite):
         if not suite.tests:
             base_tests = self.real_tests([suite.base])
+            base_tests.extend(self._wpt_test_urls_matching_paths([suite.base]))
             suite.tests = {}
             for test in base_tests:
                 suite.tests[test.replace(suite.base, suite.name, 1)] = test
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index 28827c8..522643e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -281,14 +281,72 @@
         PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
         self.assertIn('external/wpt/dom/ranges/Range-attributes.html', port.tests([]))
         self.assertNotIn('external/wpt/console/console-is-a-namespace.any.js', port.tests([]))
-        self.assertEqual(port.tests(['external']), ['external/wpt/dom/ranges/Range-attributes.html'])
-        self.assertEqual(port.tests(['external/']), ['external/wpt/dom/ranges/Range-attributes.html'])
+
+        # test.any.js shows up on the filesystem as one file but it effectively becomes two test files:
+        # test.any.html and test.any.worker.html. We should support running test.any.js by name and
+        # indirectly by specifying a parent directory.
+        self.assertEqual(port.tests(['external']),
+                         ['external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html',
+                          'external/wpt/dom/ranges/Range-attributes.html',
+                          'external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/']),
+                         ['external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html',
+                          'external/wpt/dom/ranges/Range-attributes.html',
+                          'external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
         self.assertEqual(port.tests(['external/csswg-test']), [])
-        self.assertEqual(port.tests(['external/wpt']), ['external/wpt/dom/ranges/Range-attributes.html'])
-        self.assertEqual(port.tests(['external/wpt/']), ['external/wpt/dom/ranges/Range-attributes.html'])
+        self.assertEqual(port.tests(['external/wpt']),
+                         ['external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html',
+                          'external/wpt/dom/ranges/Range-attributes.html',
+                          'external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/']),
+                         ['external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html',
+                          'external/wpt/dom/ranges/Range-attributes.html',
+                          'external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/console']),
+                         ['external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/console/']),
+                         ['external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/console/console-is-a-namespace.any.js']),
+                         ['external/wpt/console/console-is-a-namespace.any.worker.html',
+                          'external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/console/console-is-a-namespace.any.html']),
+                         ['external/wpt/console/console-is-a-namespace.any.html'])
+        self.assertEqual(port.tests(['external/wpt/dom']),
+                         ['external/wpt/dom/ranges/Range-attributes.html'])
+        self.assertEqual(port.tests(['external/wpt/dom/']),
+                         ['external/wpt/dom/ranges/Range-attributes.html'])
         self.assertEqual(port.tests(['external/wpt/dom/ranges/Range-attributes.html']),
                          ['external/wpt/dom/ranges/Range-attributes.html'])
 
+    def test_virtual_wpt_tests_paths(self):
+        port = self.make_port(with_tests=True)
+        PortTest._add_manifest_to_mock_file_system(port.host.filesystem)
+        all_wpt = [
+            'virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.html',
+            'virtual/virtual_wpt/external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html',
+            'virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.worker.html',
+            'virtual/virtual_wpt/external/wpt/dom/ranges/Range-attributes.html',
+        ]
+        dom_wpt = [
+            'virtual/virtual_wpt_dom/external/wpt/dom/ranges/Range-attributes.html',
+        ]
+
+        self.assertEqual(port.tests(['virtual/virtual_wpt/external/']), all_wpt)
+        self.assertEqual(port.tests(['virtual/virtual_wpt/external/wpt/']), all_wpt)
+        self.assertEqual(port.tests(['virtual/virtual_wpt/external/wpt/console']),
+                         ['virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.html',
+                          'virtual/virtual_wpt/external/wpt/console/console-is-a-namespace.any.worker.html'])
+
+        self.assertEqual(port.tests(['virtual/virtual_wpt_dom/external/wpt/dom/']), dom_wpt)
+        self.assertEqual(port.tests(['virtual/virtual_wpt_dom/external/wpt/dom/ranges/']), dom_wpt)
+        self.assertEqual(port.tests(['virtual/virtual_wpt_dom/external/wpt/dom/ranges/Range-attributes.html']), dom_wpt)
+
     def test_is_test_file(self):
         port = self.make_port(with_tests=True)
         is_test_file = functools.partial(Port.is_test_file, port, port.host.filesystem)
@@ -329,6 +387,16 @@
         # A file in external/wpt_automation.
         self.assertTrue(port.is_test_file(filesystem, LAYOUT_TEST_DIR + '/external/wpt_automation', 'foo.html'))
 
+    def test_is_wpt_test(self):
+        port = self.make_port(with_tests=True)
+        filesystem = port.host.filesystem
+        PortTest._add_manifest_to_mock_file_system(filesystem)
+
+        self.assertTrue(port.is_wpt_test('external/wpt/dom/ranges/Range-attributes.html'))
+        self.assertTrue(port.is_wpt_test('external/wpt/html/dom/elements/global-attributes/dir_auto-EN-L.html'))
+        self.assertFalse(port.is_wpt_test('dom/domparsing/namespaces-1.html'))
+        self.assertFalse(port.is_wpt_test('rutabaga'))
+
     def test_is_slow_wpt_test(self):
         port = self.make_port(with_tests=True)
         filesystem = port.host.filesystem
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
index af6f1fe..40774ab3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -110,9 +110,9 @@
 #
 # These numbers may need to be updated whenever we add or delete tests. This includes virtual tests.
 #
-TOTAL_TESTS = 108
+TOTAL_TESTS = 106
 TOTAL_WONTFIX = 3
-TOTAL_SKIPS = 22 + TOTAL_WONTFIX
+TOTAL_SKIPS = 21 + TOTAL_WONTFIX
 TOTAL_CRASHES = 76
 
 UNEXPECTED_PASSES = 1
@@ -126,7 +126,6 @@
     tests.add('failures/expected/device_failure.html', device_failure=True)
     tests.add('failures/expected/timeout.html', timeout=True)
     tests.add('failures/expected/leak.html', leak=True)
-    tests.add('failures/expected/needsrebaseline.html', actual_text='needsrebaseline text')
     tests.add('failures/expected/needsmanualrebaseline.html', actual_text='needsmanualrebaseline text')
     tests.add('failures/expected/image.html',
               actual_image='image_fail-pngtEXtchecksum\x00checksum_fail',
@@ -281,7 +280,6 @@
 Bug(test) failures/expected/crash.html [ Crash ]
 Bug(test) failures/expected/crash_then_text.html [ Failure ]
 Bug(test) failures/expected/image.html [ Failure ]
-Bug(test) failures/expected/needsrebaseline.html [ NeedsRebaseline ]
 Bug(test) failures/expected/needsmanualrebaseline.html [ NeedsManualRebaseline ]
 Bug(test) failures/expected/audio.html [ Failure ]
 Bug(test) failures/expected/image_checksum.html [ Failure ]
@@ -535,6 +533,8 @@
             VirtualTestSuite(prefix='skipped', base='failures/expected', args=['--virtual-arg2']),
             VirtualTestSuite(prefix='references_use_default_args', base='passes/reftest.html',
                              args=['--virtual-arg'], references_use_default_args=True),
+            VirtualTestSuite(prefix='virtual_wpt', base='external/wpt', args=['--virtual-arg']),
+            VirtualTestSuite(prefix='virtual_wpt_dom', base='external/wpt/dom', args=['--virtual-arg']),
         ]
 
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/process_json_data_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/process_json_data_unittest.py
deleted file mode 100644
index 6550980..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/process_json_data_unittest.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright (C) 2014 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.
-
-import unittest
-
-from webkitpy.layout_tests.generate_results_dashboard import ProcessJsonData
-
-
-class ProcessJsonDataTester(unittest.TestCase):
-
-    def test_check_failing_results(self):
-        valid_json_data = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'expected': 'PASS', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        valid_json_data_1 = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'expected': 'TEXT', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        valid_json_data_2 = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name_2': {
-                            'test_2.html': {'expected': 'PASS', 'actual': 'TEXT', 'is_unexpected': True}
-                        },
-                        'test_name': {
-                            'test.html': {'expected': 'TEXT', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        expected_result = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'archived_results': ['TEXT', 'PASS']}
-                        }
-                    }
-                }
-            }
-        }
-
-        process_json_data = ProcessJsonData(valid_json_data, [valid_json_data_1], [valid_json_data_2])
-        actual_result = process_json_data.generate_archived_result()
-        self.assertEqual(expected_result, actual_result)
-
-    def test_check_full_results(self):
-        valid_json_data = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name_2': {
-                            'test_2.html': {'expected': 'PASS', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        valid_json_data_1 = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'expected': 'TEXT', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        valid_json_data_2 = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name_2': {
-                            'test_2.html': {'expected': 'PASS', 'actual': 'TEXT', 'is_unexpected': True}
-                        },
-                        'test_name': {
-                            'test.html': {'expected': 'TEXT', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        expected_result = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name_2': {
-                            'test_2.html': {'archived_results': ['TEXT', 'TEXT']}
-                        }
-                    }
-                }
-            }
-        }
-
-        process_json_data = ProcessJsonData(valid_json_data, [valid_json_data_1], [valid_json_data_2])
-        actual_result = process_json_data.generate_archived_result()
-        self.assertEqual(expected_result, actual_result)
-
-    def test_null_check(self):
-        valid_json_data = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'expected': 'PASS', 'actual': 'TEXT', 'is_unexpected': True}
-                        }
-                    }
-                }
-            }
-        }
-
-        expected_result = {
-            'tests': {
-                'test_category': {
-                    'test_sub_category': {
-                        'test_name': {
-                            'test.html': {'archived_results': ['TEXT']}}
-                    }
-                }
-            }
-        }
-
-        process_json_data = ProcessJsonData(valid_json_data, [], [])
-        actual_result = process_json_data.generate_archived_result()
-        self.assertEqual(expected_result, actual_result)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index fcc8191..3160dc9 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -36,7 +36,6 @@
 from webkitpy.common import exit_codes
 from webkitpy.common.host import Host
 from webkitpy.layout_tests.controllers.manager import Manager
-from webkitpy.layout_tests.generate_results_dashboard import DashBoardGenerator
 from webkitpy.layout_tests.models import test_run_results
 from webkitpy.layout_tests.port.factory import configuration_options, platform_options
 from webkitpy.layout_tests.views import buildbot_results
@@ -606,11 +605,6 @@
             bot_printer.print_results(run_details)
             stdout.flush()
 
-            _log.debug('Generating dashboard...')
-            gen_dash_board = DashBoardGenerator(port)
-            gen_dash_board.generate()
-            _log.debug('Dashboard generated.')
-
         _log.debug('')
         _log.debug('Testing completed, Exit status: %d', run_details.exit_code)
         return run_details
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 3d0dc415..b8986b81 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -1142,7 +1142,7 @@
         # The run exit code is 0, indicating success; since we're resetting
         # baselines, it's OK for actual results to not match baselines.
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 8)
+        self.assertEqual(len(file_list), 7)
         self.assert_baselines(
             file_list, log_stream,
             'failures/unexpected/text-image-checksum',
@@ -1177,7 +1177,7 @@
             tests_included=True, host=host)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 9)
+        self.assertEqual(len(file_list), 8)
         self.assert_baselines(
             file_list, log_stream,
             'failures/unexpected/missing_text', ['.txt'])
@@ -1208,7 +1208,7 @@
             tests_included=True, host=host)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 8)
+        self.assertEqual(len(file_list), 7)
         self.assert_baselines(
             file_list, log_stream,
             'platform/test-mac-mac10.10/failures/unexpected/text-image-checksum',
@@ -1223,7 +1223,7 @@
             tests_included=True, host=host)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 6)
+        self.assertEqual(len(file_list), 5)
         self.assert_baselines(
             file_list, log_stream, 'passes/reftest', expected_extensions=[])
 
@@ -1238,7 +1238,7 @@
             tests_included=True, host=host)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 7)
+        self.assertEqual(len(file_list), 6)
         self.assert_baselines(
             file_list, log_stream, 'passes/reftest',
             expected_extensions=['.txt'])
@@ -1261,7 +1261,7 @@
             tests_included=True, host=host)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
-        self.assertEqual(len(file_list), 8)
+        self.assertEqual(len(file_list), 7)
         # We should create new image baseline only.
         self.assert_baselines(
             file_list, log_stream,
@@ -1296,7 +1296,7 @@
         file_list = host.filesystem.written_files.keys()
         # Exclude the removed file.
         file_list.remove(flag_specific_baseline_txt)
-        self.assertEqual(len(file_list), 8)
+        self.assertEqual(len(file_list), 7)
         # We should create new image baseline only.
         self.assert_baselines(
             file_list, log_stream,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations.py
index bc5929d..8a02471e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations.py
@@ -95,7 +95,7 @@
         if len(expectations) < 2:
             return False
 
-        # Don't check lines that have expectations like NeedsRebaseline or Skip.
+        # Don't check lines that have expectations like Skip.
         if self._has_unstrippable_expectations(expectations):
             return False
 
@@ -190,9 +190,12 @@
             True if at least one of the expectations is unstrippable. False
             otherwise.
         """
-        unstrippable_expectations = ('REBASELINE', 'NEEDSREBASELINE',
-                                     'NEEDSMANUALREBASELINE', 'SLOW',
-                                     'SKIP')
+        unstrippable_expectations = (
+            'NEEDSMANUALREBASELINE',
+            'REBASELINE',
+            'SKIP',
+            'SLOW',
+        )
         return any(s in expectations for s in unstrippable_expectations)
 
     def _get_builder_results_by_path(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations_unittest.py
index fcc8dc9..a955b5b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_flaky_expectations_unittest.py
@@ -167,8 +167,7 @@
             Bug(test) test/b.html [ Timeout ]
             Bug(test) test/c.html [ Failure Timeout ]
             Bug(test) test/d.html [ Rebaseline ]
-            Bug(test) test/e.html [ NeedsManualRebaseline ]
-            Bug(test) test/f.html [ NeedsRebaseline ]"""
+            Bug(test) test/e.html [ NeedsManualRebaseline ]"""
 
         self._define_builders({
             'WebKit Linux Trusty': {
@@ -265,9 +264,8 @@
         test_expectations_before = """
             # Even though the results show all passing, none of the
             # expectations are flaky so we shouldn't remove any.
-            Bug(test) test/a.html [ Failure NeedsRebaseline Pass ]
-            Bug(test) test/b.html [ Failure Pass Rebaseline ]
-            Bug(test) test/c.html [ Failure NeedsManualRebaseline Pass ]"""
+            Bug(test) test/a.html [ Failure Pass Rebaseline ]
+            Bug(test) test/b.html [ Failure NeedsManualRebaseline Pass ]"""
 
         self._define_builders({
             'WebKit Linux Trusty': {
@@ -283,7 +281,6 @@
             'WebKit Linux Trusty': {
                 'test/a.html': ['PASS', 'PASS'],
                 'test/b.html': ['PASS', 'PASS'],
-                'test/c.html': ['PASS', 'PASS']
             }
         }
         updated_expectations = (
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py
index 748a78d..b8cdd33 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py
@@ -77,7 +77,6 @@
         self._print_default("Using port '%s'" % self._port.name())
         self._print_default('Test configuration: %s' % self._port.test_configuration())
         self._print_default('View the test results at file://%s/results.html' % results_directory)
-        self._print_default('View the archived results dashboard at file://%s/dashboard.html' % results_directory)
         if self._options.order == 'random':
             self._print_default('Using random order with seed: %d' % self._options.seed)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py
index 8b33f9dd..bab8004 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py
@@ -130,7 +130,6 @@
         self.assertIn("Using port 'test-mac-mac10.10'", err.getvalue())
         self.assertIn('Test configuration: <mac10.10, x86, release>', err.getvalue())
         self.assertIn('View the test results at file:///tmp', err.getvalue())
-        self.assertIn('View the archived results dashboard at file:///tmp', err.getvalue())
         self.assertIn('Baseline search path: test-mac-mac10.10 -> test-mac-mac10.11 -> generic', err.getvalue())
         self.assertIn('Using Release build', err.getvalue())
         self.assertIn('Pixel tests enabled', err.getvalue())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py
deleted file mode 100644
index 1f2bde21..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py
+++ /dev/null
@@ -1,286 +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.
-
-"""A command to download new baselines for NeedsRebaseline tests.
-
-This command checks the list of tests with NeedsRebaseline expectations,
-and downloads the latest baselines for those tests from the results archived
-by the continuous builders.
-"""
-
-import logging
-import optparse
-import re
-import sys
-import time
-import traceback
-import urllib2
-
-from webkitpy.common.net.buildbot import Build, current_build_link
-from webkitpy.layout_tests.models.test_expectations import TestExpectations, BASELINE_SUFFIX_LIST
-from webkitpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand, TestBaselineSet
-
-
-_log = logging.getLogger(__name__)
-
-
-class AutoRebaseline(AbstractParallelRebaselineCommand):
-    name = 'auto-rebaseline'
-    help_text = 'Rebaselines any NeedsRebaseline lines in TestExpectations that have cycled through all the bots.'
-    AUTO_REBASELINE_BRANCH_NAME = 'auto-rebaseline-temporary-branch'
-    AUTO_REBASELINE_ALT_BRANCH_NAME = 'auto-rebaseline-alt-temporary-branch'
-
-    # Rietveld uploader stinks. Limit the number of rebaselines in a given patch to keep upload from failing.
-    # FIXME: http://crbug.com/263676 Obviously we should fix the uploader here.
-    MAX_LINES_TO_REBASELINE = 200
-
-    SECONDS_BEFORE_GIVING_UP = 300
-
-    def __init__(self):
-        super(AutoRebaseline, self).__init__(options=[
-            # FIXME: Remove this option.
-            self.no_optimize_option,
-            # FIXME: Remove this option.
-            self.results_directory_option,
-            optparse.make_option('--auth-refresh-token-json', help='Rietveld auth refresh JSON token.'),
-            optparse.make_option('--dry-run', action='store_true', default=False,
-                                 help='Run without creating a temporary branch, committing locally, or uploading/landing '
-                                 'changes to the remote repository.')
-        ])
-        self._blame_regex = re.compile(r'''
-                ^(\S*)      # Commit hash
-                [^(]* \(    # Whitespace and open parenthesis
-                <           # Email address is surrounded by <>
-                (
-                    [^@]+   # Username preceding @
-                    @
-                    [^@>]+  # Domain terminated by @ or >, some lines have an additional @ fragment after the email.
-                )
-                .*?([^ ]*)  # Test file name
-                \ \[        # Single space followed by opening [ for expectation specifier
-                [^[]*$      # Prevents matching previous [ for version specifiers instead of expectation specifiers
-            ''', re.VERBOSE)
-
-    def bot_revision_data(self, git):
-        revisions = []
-        for builder_name in self._release_builders():
-            result = self._tool.buildbot.fetch_results(Build(builder_name))
-            if result.run_was_interrupted():
-                _log.error("Can't rebaseline because the latest run on %s exited early.", result.builder_name())
-                return []
-            revisions.append({
-                'builder': result.builder_name(),
-                'revision': result.chromium_revision(git),
-            })
-        return revisions
-
-    @staticmethod
-    def _strip_comments(line):
-        comment_index = line.find('#')
-        if comment_index == -1:
-            comment_index = len(line)
-        return re.sub(r"\s+", ' ', line[:comment_index].strip())
-
-    def tests_to_rebaseline(self, tool, min_revision, print_revisions):
-        port = tool.port_factory.get()
-        expectations_file_path = port.path_to_generic_test_expectations_file()
-
-        tests = set()
-        revision = None
-        commit = None
-        author = None
-        bugs = set()
-        has_any_needs_rebaseline_lines = False
-
-        for line in tool.git().blame(expectations_file_path).split('\n'):
-            line = self._strip_comments(line)
-            if 'NeedsRebaseline' not in line:
-                continue
-
-            has_any_needs_rebaseline_lines = True
-
-            parsed_line = self._blame_regex.match(line)
-            if not parsed_line:
-                # Deal gracefully with inability to parse blame info for a line in TestExpectations.
-                # Parsing could fail if for example during local debugging the developer modifies
-                # TestExpectations and does not commit.
-                _log.info("Couldn't find blame info for expectations line, skipping [line=%s].", line)
-                continue
-
-            commit_hash = parsed_line.group(1)
-            commit_position = tool.git().commit_position_from_git_commit(commit_hash)
-
-            test = parsed_line.group(3)
-            if print_revisions:
-                _log.info('%s is waiting for r%s', test, commit_position)
-
-            if not commit_position or commit_position > min_revision:
-                continue
-
-            if revision and commit_position != revision:
-                continue
-
-            if not revision:
-                revision = commit_position
-                commit = commit_hash
-                author = parsed_line.group(2)
-
-            bugs.update(re.findall(r"crbug\.com\/(\d+)", line))
-            tests.add(test)
-
-            if len(tests) >= self.MAX_LINES_TO_REBASELINE:
-                _log.info('Too many tests to rebaseline in one patch. Doing the first %d.', self.MAX_LINES_TO_REBASELINE)
-                break
-
-        return tests, revision, commit, author, bugs, has_any_needs_rebaseline_lines
-
-    def commit_message(self, author, revision, commit, bugs):
-        message = 'Auto-rebaseline for r%s\n\n' % revision
-        build_link = current_build_link(self._tool)
-        if build_link:
-            message += 'Build: %s\n\n' % build_link
-        message += '%s\n\n' % self.link_to_patch(commit)
-        if bugs:
-            message += 'BUG=%s\n' % ','.join(bugs)
-        message += 'TBR=%s\n' % author
-        return message
-
-    @staticmethod
-    def link_to_patch(commit):
-        return 'https://chromium.googlesource.com/chromium/src/+/' + commit
-
-    def _make_test_baseline_set(self, tests):
-        test_baseline_set = TestBaselineSet(self._tool)
-        for builder_name in self._release_builders():
-            port_name = self._tool.builders.port_name_for_builder_name(builder_name)
-            port = self._tool.port_factory.get(port_name)
-            expectations = TestExpectations(port, include_overrides=True)
-            for test in expectations.get_needs_rebaseline_failures():
-                if test not in tests:
-                    continue
-                test_baseline_set.add(test, Build(builder_name))
-        return test_baseline_set
-
-    def _run_git_cl_command(self, options, command):
-        subprocess_command = ['git', 'cl'] + command
-        if options.verbose:
-            subprocess_command.append('--verbose')
-        if options.auth_refresh_token_json:
-            subprocess_command.append('--auth-refresh-token-json')
-            subprocess_command.append(options.auth_refresh_token_json)
-
-        process = self._tool.executive.popen(subprocess_command, stdout=self._tool.executive.PIPE,
-                                             stderr=self._tool.executive.STDOUT)
-        last_output_time = time.time()
-
-        # git cl sometimes completely hangs. Bail if we haven't gotten any output to stdout/stderr in a while.
-        while process.poll() is None and time.time() < last_output_time + self.SECONDS_BEFORE_GIVING_UP:
-            # FIXME: This doesn't make any sense. readline blocks, so all this code to
-            # try and bail is useless. Instead, we should do the readline calls on a
-            # subthread. Then the rest of this code would make sense.
-            out = process.stdout.readline().rstrip('\n')
-            if out:
-                last_output_time = time.time()
-                _log.info(out)
-
-        if process.poll() is None:
-            _log.error('Command hung: %s', subprocess_command)
-            return False
-        return True
-
-    # FIXME: Move this somewhere more general.
-    @staticmethod
-    def tree_status():
-        blink_tree_status_url = 'http://chromium-status.appspot.com/status'
-        status = urllib2.urlopen(blink_tree_status_url).read().lower()
-        if 'closed' in status or status == '0':
-            return 'closed'
-        elif 'open' in status or status == '1':
-            return 'open'
-        return 'unknown'
-
-    def execute(self, options, args, tool):
-        self._tool = tool
-
-        if not options.dry_run and tool.git().has_working_directory_changes():
-            _log.error('Cannot proceed with working directory changes. Clean working directory first.')
-            return
-
-        revision_data = self.bot_revision_data(tool.git())
-        if not revision_data:
-            return
-
-        min_revision = int(min([item['revision'] for item in revision_data]))
-        tests, revision, commit, author, bugs, _ = self.tests_to_rebaseline(
-            tool, min_revision, print_revisions=options.verbose)
-
-        if options.verbose:
-            _log.info('Min revision across all bots is %s.', min_revision)
-            for item in revision_data:
-                _log.info('%s: r%s', item['builder'], item['revision'])
-
-        if not tests:
-            _log.debug('No tests to rebaseline.')
-            return
-
-        if self.tree_status() == 'closed':
-            _log.info('Cannot proceed. Tree is closed.')
-            return
-
-        _log.info('Rebaselining %s for r%s by %s.', list(tests), revision, author)
-
-        test_baseline_set = self._make_test_baseline_set(tests)
-
-        did_switch_branches = False
-        did_finish = False
-        old_branch_name_or_ref = ''
-        rebaseline_branch_name = self.AUTO_REBASELINE_BRANCH_NAME
-        try:
-            # Save the current branch name and check out a clean branch for the patch.
-            old_branch_name_or_ref = tool.git().current_branch_or_ref()
-            if old_branch_name_or_ref == self.AUTO_REBASELINE_BRANCH_NAME:
-                rebaseline_branch_name = self.AUTO_REBASELINE_ALT_BRANCH_NAME
-            if not options.dry_run:
-                tool.git().delete_branch(rebaseline_branch_name)
-                tool.git().create_clean_branch(rebaseline_branch_name)
-                did_switch_branches = True
-
-            if test_baseline_set:
-                self.rebaseline(options, test_baseline_set)
-
-            if options.dry_run:
-                return
-
-            tool.git().commit_locally_with_message(
-                self.commit_message(author, revision, commit, bugs))
-
-            # FIXME: It would be nice if we could dcommit the patch without uploading, but still
-            # go through all the precommit hooks. For rebaselines with lots of files, uploading
-            # takes a long time and sometimes fails, but we don't want to commit if, e.g. the
-            # tree is closed.
-            did_finish = self._run_git_cl_command(options, ['upload', '-f'])
-
-            if did_finish:
-                # Uploading can take a very long time. Do another pull to make sure TestExpectations is up to date,
-                # so the dcommit can go through.
-                # FIXME: Log the pull and dcommit stdout/stderr to the log-server.
-                tool.executive.run_command(['git', 'pull'])
-
-                self._run_git_cl_command(options, ['land', '-f', '-v'])
-        except OSError:
-            traceback.print_exc(file=sys.stderr)
-        finally:
-            if did_switch_branches:
-                if did_finish:
-                    # Close the issue if dcommit failed.
-                    issue_already_closed = tool.executive.run_command(
-                        ['git', 'config', 'branch.%s.rietveldissue' % rebaseline_branch_name],
-                        return_exit_code=True)
-                    if not issue_already_closed:
-                        self._run_git_cl_command(options, ['set_close'])
-
-                tool.git().ensure_cleanly_tracking_remote_master()
-                if old_branch_name_or_ref:
-                    tool.git().checkout_branch(old_branch_name_or_ref)
-                tool.git().delete_branch(rebaseline_branch_name)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py
deleted file mode 100644
index bbec1ad..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py
+++ /dev/null
@@ -1,575 +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.
-
-import optparse
-
-from webkitpy.common.net.buildbot import Build
-from webkitpy.common.net.layout_test_results import LayoutTestResults
-from webkitpy.common.system.executive_mock import MockExecutive
-from webkitpy.layout_tests.builder_list import BuilderList
-from webkitpy.tool.commands.auto_rebaseline import AutoRebaseline
-from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase
-from webkitpy.tool.commands.rebaseline_unittest import MockLineRemovingExecutive
-
-
-class TestAutoRebaseline(BaseTestCase):
-    command_constructor = AutoRebaseline
-
-    def _write_test_file(self, port, path, contents):
-        abs_path = self.tool.filesystem.join(port.layout_tests_dir(), path)
-        self.tool.filesystem.write_text_file(abs_path, contents)
-
-    def _execute_with_mock_options(self, auth_refresh_token_json=None, commit_author=None, dry_run=False):
-        self.command.execute(
-            optparse.Values({
-                'optimize': True,
-                'verbose': False,
-                'results_directory': False,
-                'auth_refresh_token_json': auth_refresh_token_json,
-                'commit_author': commit_author,
-                'dry_run': dry_run
-            }),
-            [],
-            self.tool)
-
-    def setUp(self):
-        super(TestAutoRebaseline, self).setUp()
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-            'MOCK Precise': {'port_name': 'test-linux-precise', 'specifiers': ['Precise', 'Release']},
-            'MOCK Trusty': {'port_name': 'test-linux-trusty', 'specifiers': ['Trusty', 'Release']},
-            'MOCK Win7': {'port_name': 'test-win-win7', 'specifiers': ['Win7', 'Release']},
-            'MOCK Win7 (dbg)': {'port_name': 'test-win-win7', 'specifiers': ['Win7', 'Debug']},
-        })
-        self.command.latest_revision_processed_on_all_bots = lambda: 9000
-        self.command.bot_revision_data = lambda git: [{'builder': 'MOCK Win7', 'revision': '9000'}]
-
-    def test_release_builders(self):
-        # Testing private method - pylint: disable=protected-access
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11 (dbg)': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Debug']},
-        })
-        self.assertEqual(self.command._release_builders(), ['MOCK Mac10.10'])
-
-    def test_tests_to_rebaseline(self):
-        def blame(_):
-            return """
-624c3081c0 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Failure ]
-624c3081c0 path/to/TestExpectations                   (<foobarbaz1@chromium.org@bbb929c8-8fbe-4397-9dbb-9b2b20218538> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline-email-with-hash.html [ Failure ]
-624c3081c0 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) path/to/rebaseline-without-bug-number.html [ NeedsRebaseline ]
-624c3081c0 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/rebaseline-with-modifiers.html [ NeedsRebaseline ]
-624c3081c0 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   12) crbug.com/24182 crbug.com/234 path/to/rebaseline-without-modifiers.html [ NeedsRebaseline ]
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org@bbb929c8-8fbe-4397-9dbb-9b2b20218538> 2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/rebaseline-new-revision.html [ NeedsRebaseline ]
-624caaaaaa path/to/TestExpectations                   (<foo@chromium.org>        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
-0000000000 path/to/TestExpectations                   (<foo@chromium.org@@bbb929c8-8fbe-4397-9dbb-9b2b20218538>        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        min_revision = 9000
-        self.assertEqual(self.command.tests_to_rebaseline(self.tool, min_revision, print_revisions=False), (
-            set(['path/to/rebaseline-without-bug-number.html',
-                 'path/to/rebaseline-with-modifiers.html', 'path/to/rebaseline-without-modifiers.html']),
-            5678,
-            '624c3081c0',
-            'foobarbaz1@chromium.org',
-            set(['24182', '234']),
-            True))
-
-    def test_tests_to_rebaseline_over_limit(self):
-        def blame(_):
-            result = ''
-            for i in range(0, self.command.MAX_LINES_TO_REBASELINE + 1):
-                result += ('624c3081c0 path/to/TestExpectations                   '
-                           '(<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) '
-                           'crbug.com/24182 path/to/rebaseline-%s.html [ NeedsRebaseline ]\n' % i)
-            return result
-        self.tool.git().blame = blame
-
-        expected_list_of_tests = []
-        for i in range(0, self.command.MAX_LINES_TO_REBASELINE):
-            expected_list_of_tests.append('path/to/rebaseline-%s.html' % i)
-
-        min_revision = 9000
-        self.assertEqual(self.command.tests_to_rebaseline(self.tool, min_revision, print_revisions=False), (
-            set(expected_list_of_tests),
-            5678,
-            '624c3081c0',
-            'foobarbaz1@chromium.org',
-            set(['24182']),
-            True))
-
-    def test_commit_message(self):
-        author = 'foo@chromium.org'
-        revision = 1234
-        commit = 'abcd567'
-        bugs = set()
-        self.assertEqual(self.command.commit_message(author, revision, commit, bugs),
-                         'Auto-rebaseline for r1234\n\n'
-                         'https://chromium.googlesource.com/chromium/src/+/abcd567\n\n'
-                         'TBR=foo@chromium.org\n')
-
-        bugs = set(['234', '345'])
-        self.assertEqual(self.command.commit_message(author, revision, commit, bugs),
-                         'Auto-rebaseline for r1234\n\n'
-                         'https://chromium.googlesource.com/chromium/src/+/abcd567\n\n'
-                         'BUG=234,345\n'
-                         'TBR=foo@chromium.org\n')
-
-        self.tool.environ['BUILDBOT_MASTERNAME'] = 'my.master'
-        self.tool.environ['BUILDBOT_BUILDERNAME'] = 'b'
-        self.tool.environ['BUILDBOT_BUILDNUMBER'] = '123'
-        self.assertEqual(self.command.commit_message(author, revision, commit, bugs),
-                         'Auto-rebaseline for r1234\n\n'
-                         'Build: https://build.chromium.org/p/my.master/builders/b/builds/123\n\n'
-                         'https://chromium.googlesource.com/chromium/src/+/abcd567\n\n'
-                         'BUG=234,345\n'
-                         'TBR=foo@chromium.org\n')
-
-    def test_no_needs_rebaseline_lines(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Failure ]
-"""
-        self.tool.git().blame = blame
-
-        self._execute_with_mock_options()
-        self.assertEqual(self.tool.executive.calls, [])
-
-    def test_execute(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) # Test NeedsRebaseline being in a comment doesn't bork parsing.
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Failure ]
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-06-14 20:18:46 +0000   11) crbug.com/24182 [ Mac10.11 ] fast/dom/prototype-strawberry.html [ NeedsRebaseline ]
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   12) crbug.com/24182 fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
-624caaaaaa path/to/TestExpectations                   (<foo@chromium.org>        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
-0000000000 path/to/TestExpectations                   (<foo@chromium.org>        2013-04-28 04:52:41 +0000   12) crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        # Have prototype-chocolate only fail on "MOCK Mac10.11",
-        # and pass on "Mock Mac10.10".
-        self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'prototype-taco.html': {
-                            'expected': 'PASS',
-                            'actual': 'PASS TEXT',
-                            'is_unexpected': True
-                        },
-                        'prototype-chocolate.html': {
-                            'expected': 'FAIL',
-                            'actual': 'PASS'
-                        },
-                        'prototype-strawberry.html': {
-                            'expected': 'PASS',
-                            'actual': 'IMAGE PASS',
-                            'is_unexpected': True
-                        }
-                    }
-                }
-            }
-        }))
-        self.tool.buildbot.set_results(Build('MOCK Mac10.10'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'prototype-taco.html': {
-                            'expected': 'PASS',
-                            'actual': 'PASS',
-                        },
-                        'prototype-chocolate.html': {
-                            'expected': 'FAIL',
-                            'actual': 'FAIL'
-                        },
-                        'prototype-strawberry.html': {
-                            'expected': 'PASS',
-                            'actual': 'PASS',
-                        }
-                    }
-                }
-            }
-        }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Rebaseline ]
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-crbug.com/24182 [ Mac10.11 ] fast/dom/prototype-strawberry.html [ NeedsRebaseline ]
-crbug.com/24182 fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
-crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
-crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-        self._write_test_file(test_port, 'fast/dom/prototype-strawberry.html', 'Dummy test contents')
-        self._write_test_file(test_port, 'fast/dom/prototype-chocolate.html', 'Dummy test contents')
-
-        self.tool.executive = MockLineRemovingExecutive()
-
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-        })
-
-        self.command.tree_status = lambda: 'closed'
-        self._execute_with_mock_options()
-        self.assertEqual(self.tool.executive.calls, [])
-
-        self.command.tree_status = lambda: 'open'
-        self.tool.executive.full_calls = []
-        self._execute_with_mock_options()
-
-        self.assertEqual(self.tool.executive.calls, [
-            [
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'fast/dom/prototype-strawberry.html',
-                    '--suffixes', 'png',
-                    '--port-name', 'test-mac-mac10.11',
-                ],
-                [
-                    'python', 'echo', 'copy-existing-baselines-internal',
-                    '--test', 'fast/dom/prototype-taco.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                ],
-            ],
-            [
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'fast/dom/prototype-strawberry.html',
-                    '--suffixes', 'png',
-                    '--port-name', 'test-mac-mac10.11',
-                    '--builder', 'MOCK Mac10.11',
-                ],
-                [
-                    'python', 'echo', 'rebaseline-test-internal',
-                    '--test', 'fast/dom/prototype-taco.html',
-                    '--suffixes', 'txt',
-                    '--port-name', 'test-mac-mac10.11',
-                    '--builder', 'MOCK Mac10.11',
-                ],
-            ],
-            [
-                [
-                    'python', 'echo', 'optimize-baselines',
-                    '--suffixes', 'png',
-                    'fast/dom/prototype-strawberry.html',
-                ],
-                [
-                    'python', 'echo', 'optimize-baselines',
-                    '--suffixes', 'txt',
-                    'fast/dom/prototype-taco.html',
-                ],
-            ],
-            ['git', 'cl', 'upload', '-f'],
-            ['git', 'pull'],
-            ['git', 'cl', 'land', '-f', '-v'],
-            ['git', 'config', 'branch.auto-rebaseline-temporary-branch.rietveldissue'],
-            ['git', 'cl', 'set_close'],
-        ])
-
-        # The mac ports should both be removed since they're the only ones in builders._exact_matches.
-        self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
-crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Rebaseline ]
-Bug(foo) [ Linux Win ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
-crbug.com/24182 [ Linux Win ] fast/dom/prototype-chocolate.html [ NeedsRebaseline ]
-crbug.com/24182 path/to/not-cycled-through-bots.html [ NeedsRebaseline ]
-crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
-""")
-
-    def test_execute_git_cl_hangs(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        # Have prototype-chocolate only fail on "MOCK Mac10.11".
-        self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'prototype-taco.html': {
-                            'expected': 'PASS',
-                            'actual': 'PASS TEXT',
-                            'is_unexpected': True
-                        }
-                    }
-                }
-            }
-        }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-        })
-
-        self.command.SECONDS_BEFORE_GIVING_UP = 0
-        self.command.tree_status = lambda: 'open'
-        self.tool.executive = MockExecutive()
-        self.tool.executive.full_calls = []
-        self._execute_with_mock_options()
-
-        self.assertEqual(self.tool.executive.calls, [
-            [[
-                'python', 'echo', 'copy-existing-baselines-internal',
-                '--test', 'fast/dom/prototype-taco.html',
-                '--suffixes', 'txt',
-                '--port-name', 'test-mac-mac10.11',
-            ]],
-            [[
-                'python', 'echo', 'rebaseline-test-internal',
-                '--test', 'fast/dom/prototype-taco.html',
-                '--suffixes', 'txt',
-                '--port-name', 'test-mac-mac10.11',
-                '--builder', 'MOCK Mac10.11',
-            ]],
-            [[
-                'python', 'echo', 'optimize-baselines',
-                '--suffixes', 'txt',
-                'fast/dom/prototype-taco.html',
-            ]],
-            ['git', 'cl', 'upload', '-f'],
-        ])
-
-    def test_execute_test_passes_everywhere(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
-            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
-                'tests': {
-                    'fast': {
-                        'dom': {
-                            'prototype-taco.html': {
-                                'expected': 'FAIL',
-                                'actual': 'PASS',
-                                'is_unexpected': True
-                            }
-                        }
-                    }
-                }
-            }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-
-        self.tool.executive = MockLineRemovingExecutive()
-
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-        })
-
-        self.command.tree_status = lambda: 'open'
-        self._execute_with_mock_options()
-        self.assertEqual(self.tool.executive.calls, [
-            ['git', 'cl', 'upload', '-f'],
-            ['git', 'pull'],
-            ['git', 'cl', 'land', '-f', '-v'],
-            ['git', 'config', 'branch.auto-rebaseline-temporary-branch.rietveldissue'],
-            ['git', 'cl', 'set_close'],
-        ])
-
-        # The mac ports should both be removed since they're the only ones in builders._exact_matches.
-        self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
-Bug(foo) [ Linux Win ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-    def test_execute_use_alternate_rebaseline_branch(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'prototype-taco.html': {
-                            'expected': 'FAIL',
-                            'actual': 'PASS',
-                            'is_unexpected': True
-                        }
-                    }
-                }
-            }
-        }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-
-        self.tool.executive = MockLineRemovingExecutive()
-
-        self.tool.builders = BuilderList({
-            'MOCK Win7': {'port_name': 'test-win-win7', 'specifiers': ['Win7', 'Release']},
-        })
-        old_branch_name = self.tool.git().current_branch_or_ref
-        try:
-            self.command.tree_status = lambda: 'open'
-            self.tool.git().current_branch_or_ref = lambda: 'auto-rebaseline-temporary-branch'
-            self._execute_with_mock_options()
-            self.assertEqual(self.tool.executive.calls, [
-                ['git', 'cl', 'upload', '-f'],
-                ['git', 'pull'],
-                ['git', 'cl', 'land', '-f', '-v'],
-                ['git', 'config', 'branch.auto-rebaseline-alt-temporary-branch.rietveldissue'],
-                ['git', 'cl', 'set_close'],
-            ])
-
-            self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
-Bug(foo) [ Linux Mac Win10 ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-        finally:
-            self.tool.git().current_branch_or_ref = old_branch_name
-
-    def test_execute_stuck_on_alternate_rebaseline_branch(self):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
-            'tests': {
-                'fast': {
-                    'dom': {
-                        'prototype-taco.html': {
-                            'expected': 'FAIL',
-                            'actual': 'PASS',
-                            'is_unexpected': True
-                        }
-                    }
-                }
-            }
-        }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-
-        self.tool.executive = MockLineRemovingExecutive()
-
-        self.tool.builders = BuilderList({
-            'MOCK Win7': {'port_name': 'test-win-win7', 'specifiers': ['Win7', 'Release']},
-        })
-        old_branch_name = self.tool.git().current_branch_or_ref
-        try:
-            self.command.tree_status = lambda: 'open'
-            self.tool.git().current_branch_or_ref = lambda: 'auto-rebaseline-alt-temporary-branch'
-            self._execute_with_mock_options()
-            self.assertEqual(self.tool.executive.calls, [
-                ['git', 'cl', 'upload', '-f'],
-                ['git', 'pull'],
-                ['git', 'cl', 'land', '-f', '-v'],
-                ['git', 'config', 'branch.auto-rebaseline-temporary-branch.rietveldissue'],
-                ['git', 'cl', 'set_close'],
-            ])
-
-            self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
-Bug(foo) [ Linux Mac Win10 ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-        finally:
-            self.tool.git().current_branch_or_ref = old_branch_name
-
-    def _basic_execute_test(self, expected_executive_calls, auth_refresh_token_json=None, commit_author=None, dry_run=False):
-        def blame(_):
-            return """
-6469e754a1 path/to/TestExpectations                   (<foobarbaz1@chromium.org> 2013-04-28 04:52:41 +0000   13) Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-"""
-        self.tool.git().blame = blame
-
-        test_port = self.tool.port_factory.get('test')
-
-        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
-            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
-                'tests': {
-                    'fast': {
-                        'dom': {
-                            'prototype-taco.html': {
-                                'expected': 'FAIL',
-                                'actual': 'PASS',
-                                'is_unexpected': True
-                            }
-                        }
-                    }
-                }
-            }))
-
-        self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
-Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-        self._write_test_file(test_port, 'fast/dom/prototype-taco.html', 'Dummy test contents')
-
-        self.tool.executive = MockLineRemovingExecutive()
-
-        self.tool.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-        })
-
-        self.command.tree_status = lambda: 'open'
-        self._execute_with_mock_options(auth_refresh_token_json=auth_refresh_token_json,
-                                        commit_author=commit_author, dry_run=dry_run)
-        self.assertEqual(self.tool.executive.calls, expected_executive_calls)
-
-        # The mac ports should both be removed since they're the only ones in builders._exact_matches.
-        self.assertEqual(self.tool.filesystem.read_text_file(test_port.path_to_generic_test_expectations_file()), """
-Bug(foo) [ Linux Win ] fast/dom/prototype-taco.html [ NeedsRebaseline ]
-""")
-
-    def test_execute_with_rietveld_auth_refresh_token(self):
-        rietveld_refresh_token = '/creds/refresh_tokens/test_rietveld_token'
-        self._basic_execute_test(
-            [
-                ['git', 'cl', 'upload', '-f', '--auth-refresh-token-json', rietveld_refresh_token],
-                ['git', 'pull'],
-                ['git', 'cl', 'land', '-f', '-v', '--auth-refresh-token-json', rietveld_refresh_token],
-                ['git', 'config', 'branch.auto-rebaseline-temporary-branch.rietveldissue'],
-                ['git', 'cl', 'set_close', '--auth-refresh-token-json', rietveld_refresh_token],
-            ],
-            auth_refresh_token_json=rietveld_refresh_token)
-
-    def test_execute_with_dry_run(self):
-        self._basic_execute_test([], dry_run=True)
-        self.assertEqual(self.tool.git().local_commits(), [])
-
-    def test_bot_revision_data(self):
-        self._setup_mock_build_data()
-        self.assertEqual(
-            self.command.bot_revision_data(self.tool.git()),
-            [{'builder': 'MOCK Win7', 'revision': '9000'}])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
index 9745818..33f4acb2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -339,9 +339,7 @@
 
         # This is so we remove lines for builders that skip this test, e.g. Android skips most
         # tests and we don't want to leave stray [ Android ] lines in TestExpectations..
-        # This is only necessary for "webkit-patch rebaseline" and for rebaselining expected
-        # failures from garden-o-matic. rebaseline-expectations and auto-rebaseline will always
-        # pass the exact set of ports to rebaseline.
+        # This is only necessary for "webkit-patch rebaseline".
         for port_name in self._tool.port_factory.all_port_names():
             port = self._tool.port_factory.get(port_name)
             generic_expectations = TestExpectations(port, tests=tests, include_overrides=False)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
index d7eac77..a68714d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -101,6 +101,8 @@
                 self.mac_port.layout_tests_dir(), test)
             self._write(path, 'contents')
 
+        self.mac_port.host.filesystem.write_text_file('/test.checkout/LayoutTests/external/wpt/MANIFEST.json', '{}')
+
     def tearDown(self):
         BaseTestCase.tearDown(self)
         LoggingTestCase.tearDown(self)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index b5b7e1347..b3fadaa 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -173,7 +173,7 @@
             'tests': {
                 'userscripts': {
                     'first-test.html': {
-                        'expected': 'NEEDSREBASELINE',
+                        'expected': 'REBASELINE',
                         'actual': 'PASS'
                     }
                 }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
index b8c7881..9224676 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
@@ -42,7 +42,6 @@
 
 from webkitpy.common.host import Host
 from webkitpy.tool.commands.analyze_baselines import AnalyzeBaselines
-from webkitpy.tool.commands.auto_rebaseline import AutoRebaseline
 from webkitpy.tool.commands.command import HelpPrintingOptionParser
 from webkitpy.tool.commands.copy_existing_baselines import CopyExistingBaselines
 from webkitpy.tool.commands.flaky_tests import FlakyTests
@@ -81,7 +80,6 @@
         self._path = path
         self.commands = [
             AnalyzeBaselines(),
-            AutoRebaseline(),
             CopyExistingBaselines(),
             CrashLog(),
             FlakyTests(),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
index 25be40d..128a038 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -13,6 +13,7 @@
 import logging
 
 from webkitpy.common.path_finder import PathFinder
+from webkitpy.common.memoized import memoized
 
 _log = logging.getLogger(__file__)
 
@@ -23,6 +24,7 @@
         # TODO(tkent): Create a Manifest object by Manifest.from_json().
         # See ../thirdparty/wpt/wpt/tools/manifest/manifest.py.
         self.raw_dict = json.loads(json_content)
+        self.test_types = ('manual', 'reftest', 'testharness')
 
     def _items_for_path(self, path_in_wpt):
         """Returns manifest items for the given WPT path, or None if not found.
@@ -35,28 +37,50 @@
         it will be a list with three items ([url, references, extras]).
         """
         items = self.raw_dict['items']
-        if path_in_wpt in items['manual']:
-            return items['manual'][path_in_wpt]
-        elif path_in_wpt in items['reftest']:
-            return items['reftest'][path_in_wpt]
-        elif path_in_wpt in items['testharness']:
-            return items['testharness'][path_in_wpt]
+        for test_type in self.test_types:
+            if path_in_wpt in items[test_type]:
+                return items[test_type][path_in_wpt]
         return None
 
+    @memoized
+    def all_urls(self):
+        """Returns a set of the urls for all items in the manifest."""
+        urls = set()
+        if 'items' in self.raw_dict:
+            items = self.raw_dict['items']
+            for category in self.test_types:
+                if category in items:
+                    for records in items[category].values():
+                        urls.update([item[0] for item in records])
+        return urls
+
+    @memoized
+    def all_wpt_tests(self):
+        if 'items' not in self.raw_dict:
+            return []
+
+        all_tests = []
+        for test_type in self.test_types:
+            for path_in_wpt in self.raw_dict['items'][test_type]:
+                all_tests.append(path_in_wpt)
+        return all_tests
+
     def is_test_file(self, path_in_wpt):
         return self._items_for_path(path_in_wpt) is not None
 
+    def is_test_url(self, url):
+        """Checks if url is a valid test in the manifest.
+
+        The url must be the WPT test name with a leading slash (/).
+        """
+        if url[0] != '/':
+            raise Exception('Test url missing leading /: %s' % url)
+        return url in self.all_urls()
+
     def file_path_to_url_paths(self, path_in_wpt):
         manifest_items = self._items_for_path(path_in_wpt)
         assert manifest_items is not None
-        if len(manifest_items) != 1:
-            return []
-        url = manifest_items[0][0]
-        if url[1:] != path_in_wpt:
-            # TODO(tkent): foo.any.js and bar.worker.js should be accessed
-            # as foo.any.html, foo.any.worker, and bar.worker with WPTServe.
-            return []
-        return [path_in_wpt]
+        return [item[0][1:] for item in manifest_items]
 
     @staticmethod
     def _get_extras_from_item(item):
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 8f65863..f817d82f 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -806,7 +806,7 @@
   export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"
 
   # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
+  js_bindings_mode = "both"
 }
 
 # The offscreen_canvas_mojo_bindings is separated from the rest of mojom files
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 91dbd53..9a31258 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1589,6 +1589,7 @@
   kLinearAccelerationSensorConstructor = 2051,
   kReportUriMultipleEndpoints = 2052,
   kReportUriSingleEndpoint = 2053,
+  kV8ConstructorNonUndefinedPrimitiveReturn = 2054,
 
   // 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/libaddressinput/chromium/chrome_address_validator.cc b/third_party/libaddressinput/chromium/chrome_address_validator.cc
index f76bcbd1..232ef1e 100644
--- a/third_party/libaddressinput/chromium/chrome_address_validator.cc
+++ b/third_party/libaddressinput/chromium/chrome_address_validator.cc
@@ -60,18 +60,39 @@
   supplier_->LoadRules(region_code, *rules_loaded_);
 }
 
-std::vector<std::string> AddressValidator::GetRegionSubKeys(
-    const std::string& region_code) {
+std::vector<std::pair<std::string, std::string>>
+AddressValidator::GetRegionSubKeys(const std::string& region_code,
+                                   const std::string& language) {
+  std::vector<std::pair<std::string, std::string>> subkeys_codes_names;
   if (!AreRulesLoadedForRegion(region_code))
-    return std::vector<std::string>();
+    return subkeys_codes_names;
 
   auto rules = supplier_->GetRulesForRegion(region_code);
   auto rule_iterator = rules.find("data/" + region_code);
-
+  // This happens if the rules are bad.
   if (rule_iterator == rules.end() || !rule_iterator->second)
-    return std::vector<std::string>();
+    return subkeys_codes_names;
 
-  return rule_iterator->second->GetSubKeys();
+  auto subkeys_codes = rule_iterator->second->GetSubKeys();
+
+  // If the device language is available, show the names in that language.
+  // Otherwise, show the default names.
+  std::string lang_suffix = "";
+  if (rules.find("data/" + region_code + "--" + language) != rules.end())
+    lang_suffix = "--" + language;  // ex: --fr
+
+  for (auto subkey_code : subkeys_codes) {
+    auto rule = rules.find("data/" + region_code + '/' + subkey_code +
+                           lang_suffix);  // exp: data/CA/QC--fr
+    // This happens if the rules are bad.
+    if (rule == rules.end() || !rule_iterator->second)
+      continue;
+    auto subkey_name = rule->second->GetName();
+    if (subkey_name.empty())  // For some cases, the name is not available.
+      subkey_name = subkey_code;
+    subkeys_codes_names.push_back(make_pair(subkey_code, subkey_name));
+  }
+  return subkeys_codes_names;
 }
 
 AddressValidator::Status AddressValidator::ValidateAddress(
diff --git a/third_party/libaddressinput/chromium/chrome_address_validator.h b/third_party/libaddressinput/chromium/chrome_address_validator.h
index 7a2c7c6..ef1f434 100644
--- a/third_party/libaddressinput/chromium/chrome_address_validator.h
+++ b/third_party/libaddressinput/chromium/chrome_address_validator.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/macros.h"
@@ -95,11 +96,13 @@
   virtual void LoadRules(const std::string& region_code);
 
   // Returns the list of sub-regions (recorded as sub-keys) of the region
-  // (recorded as rule) indicated by |region_code|. So, if the |region_code| is
+  // (recorded as rule) indicated by |region_code|, while the device language
+  // is set to |language|. So, if the |region_code| is
   // a country code, sub-region means the country's admin area.
   // This function should be called when the rules are loaded.
-  virtual std::vector<std::string> GetRegionSubKeys(
-      const std::string& region_code);
+  virtual std::vector<std::pair<std::string, std::string>> GetRegionSubKeys(
+      const std::string& region_code,
+      const std::string& language);
 
   // Validates the |address| and populates |problems| with the validation
   // problems, filtered according to the |filter| parameter.
diff --git a/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc b/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
index 54c37e4..4116f5d 100644
--- a/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
+++ b/third_party/libaddressinput/chromium/chrome_address_validator_unittest.cc
@@ -120,23 +120,83 @@
 
 TEST_F(AddressValidatorTest, SubKeysLoaded) {
   const std::string country_code = "US";
-  const std::string first_state = "AL";
+  const std::string state_code = "AL";
+  const std::string state_name = "Alabama";
+  const std::string language = "en";
 
   validator_->LoadRules(country_code);
-  std::vector<std::string> sub_keys =
-      validator_->GetRegionSubKeys(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
   ASSERT_FALSE(sub_keys.empty());
-  ASSERT_EQ(sub_keys[0], first_state);
+  ASSERT_EQ(state_code, sub_keys[0].first);
+  ASSERT_EQ(state_name, sub_keys[0].second);
+}
+
+TEST_F(AddressValidatorTest, SubKeysLoaded_DefaultLanguage) {
+  const std::string country_code = "CA";
+  const std::string province_code = "BC";
+  const std::string province_name = "British Columbia";
+  const std::string language = "en";
+
+  validator_->LoadRules(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
+  ASSERT_FALSE(sub_keys.empty());
+  ASSERT_EQ(province_code, sub_keys[1].first);
+  ASSERT_EQ(province_name, sub_keys[1].second);
+}
+
+TEST_F(AddressValidatorTest, SubKeysLoaded_NonDefaultLanguage) {
+  const std::string country_code = "CA";
+  const std::string province_code = "BC";
+  const std::string province_name = "Colombie-Britannique";
+  const std::string language = "fr";
+
+  validator_->LoadRules(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
+  ASSERT_FALSE(sub_keys.empty());
+  ASSERT_EQ(province_code, sub_keys[1].first);
+  ASSERT_EQ(province_name, sub_keys[1].second);
+}
+
+TEST_F(AddressValidatorTest, SubKeysLoaded_LanguageNotAvailable) {
+  const std::string country_code = "CA";
+  const std::string province_code = "BC";
+  const std::string province_name = "British Columbia";
+  const std::string language = "es";
+
+  validator_->LoadRules(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
+  ASSERT_FALSE(sub_keys.empty());
+  ASSERT_EQ(province_code, sub_keys[1].first);
+  ASSERT_EQ(province_name, sub_keys[1].second);
+}
+
+TEST_F(AddressValidatorTest, SubKeysLoaded_NamesNotAvailable) {
+  const std::string country_code = "ES";
+  const std::string province_code = "A Coruña";
+  const std::string province_name = "A Coruña";
+  const std::string language = "es";
+
+  validator_->LoadRules(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
+  ASSERT_FALSE(sub_keys.empty());
+  ASSERT_EQ(province_code, sub_keys[0].first);
+  ASSERT_EQ(province_name, sub_keys[0].second);
 }
 
 TEST_F(AddressValidatorTest, SubKeysNotExist) {
   const std::string country_code = "OZ";
+  const std::string language = "en";
 
   set_expected_status(AddressValidator::RULES_UNAVAILABLE);
 
   validator_->LoadRules(country_code);
-  std::vector<std::string> sub_keys =
-      validator_->GetRegionSubKeys(country_code);
+  std::vector<std::pair<std::string, std::string>> sub_keys =
+      validator_->GetRegionSubKeys(country_code, language);
   ASSERT_TRUE(sub_keys.empty());
 }
 
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 22f1c12..62abb57 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Saturday June 24 2017
+Date: Friday July 07 2017
 Branch: master
-Commit: ec4afbf74a4beebadee3e1b15b43c5d4e3d3bd1c
+Commit: 4e16f7070354fa91c1a617ee18335e580a0b8c8c
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index fc955f4..fe97770 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -190,8 +190,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -331,7 +329,9 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_impl_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse2.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse4.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_sse2.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/transpose_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/txfm_common_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_asm_stubs.c",
@@ -447,6 +447,7 @@
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/quantize_sse4.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/temporal_filter_sse4.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_idct4x4_add_sse4.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_idct8x8_add_sse4.c",
 ]
 libvpx_srcs_x86_avx = [ "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_diamond_search_sad_avx.c" ]
 libvpx_srcs_x86_avx2 = [
@@ -647,8 +648,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -788,7 +787,9 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_impl_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse2.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse4.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_sse2.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/transpose_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/txfm_common_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_asm_stubs.c",
@@ -911,6 +912,7 @@
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/quantize_sse4.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/temporal_filter_sse4.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_idct4x4_add_sse4.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_idct8x8_add_sse4.c",
 ]
 libvpx_srcs_x86_64_avx = [ "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_diamond_search_sad_avx.c" ]
 libvpx_srcs_x86_64_avx2 = [
@@ -1107,8 +1109,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -1473,8 +1473,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_error_neon.c",
@@ -1580,6 +1578,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct16x16_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct32x32_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_neon.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_partial_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fwd_txfm_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/hadamard_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.c",
@@ -1861,8 +1860,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -2070,6 +2067,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct16x16_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct32x32_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_neon.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_partial_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fwd_txfm_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/hadamard_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.c",
@@ -2293,8 +2291,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_denoiser_neon.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/arm/neon/vp9_error_neon.c",
@@ -2400,6 +2396,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct16x16_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct32x32_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_neon.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fdct_partial_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/fwd_txfm_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/hadamard_neon.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.c",
@@ -2673,8 +2670,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -3015,8 +3010,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
@@ -3357,8 +3350,6 @@
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_detokenize.h",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.c",
   "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dsubexp.h",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.c",
-  "//third_party/libvpx/source/libvpx/vp9/decoder/vp9_dthread.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_alt_ref_aq.h",
   "//third_party/libvpx/source/libvpx/vp9/encoder/vp9_aq_360.c",
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
index c52128f..b978840 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
@@ -218,24 +218,28 @@
 #define vpx_fdct16x16 vpx_fdct16x16_neon
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct16x16_1 vpx_fdct16x16_1_c
+void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct16x16_1 vpx_fdct16x16_1_neon
 
 void vpx_fdct32x32_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct32x32_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct32x32 vpx_fdct32x32_neon
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_1 vpx_fdct32x32_1_c
+void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_1 vpx_fdct32x32_1_neon
 
 void vpx_fdct32x32_rd_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_rd vpx_fdct32x32_rd_c
+void vpx_fdct32x32_rd_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_rd vpx_fdct32x32_rd_neon
 
 void vpx_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct4x4 vpx_fdct4x4_neon
 
 void vpx_fdct4x4_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct4x4_1 vpx_fdct4x4_1_c
+void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct4x4_1 vpx_fdct4x4_1_neon
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *output, int stride);
@@ -444,7 +448,8 @@
 #define vpx_sad16x16 vpx_sad16x16_neon
 
 unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x16_avg vpx_sad16x16_avg_c
+unsigned int vpx_sad16x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x16_avg vpx_sad16x16_avg_neon
 
 void vpx_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x16x3 vpx_sad16x16x3_c
@@ -457,10 +462,12 @@
 #define vpx_sad16x16x8 vpx_sad16x16x8_c
 
 unsigned int vpx_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad16x32 vpx_sad16x32_c
+unsigned int vpx_sad16x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad16x32 vpx_sad16x32_neon
 
 unsigned int vpx_sad16x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x32_avg vpx_sad16x32_avg_c
+unsigned int vpx_sad16x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x32x4d vpx_sad16x32x4d_c
@@ -470,7 +477,8 @@
 #define vpx_sad16x8 vpx_sad16x8_neon
 
 unsigned int vpx_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x8_avg vpx_sad16x8_avg_c
+unsigned int vpx_sad16x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x8_avg vpx_sad16x8_avg_neon
 
 void vpx_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
@@ -482,10 +490,12 @@
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
 
 unsigned int vpx_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x16 vpx_sad32x16_c
+unsigned int vpx_sad32x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x16 vpx_sad32x16_neon
 
 unsigned int vpx_sad32x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x16_avg vpx_sad32x16_avg_c
+unsigned int vpx_sad32x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x16x4d vpx_sad32x16x4d_c
@@ -495,7 +505,8 @@
 #define vpx_sad32x32 vpx_sad32x32_neon
 
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x32_avg vpx_sad32x32_avg_c
+unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
 void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x3 vpx_sad32x32x3_c
@@ -508,10 +519,12 @@
 #define vpx_sad32x32x8 vpx_sad32x32x8_c
 
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x64 vpx_sad32x64_c
+unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x64 vpx_sad32x64_neon
 
 unsigned int vpx_sad32x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x64_avg vpx_sad32x64_avg_c
+unsigned int vpx_sad32x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x64x4d vpx_sad32x64x4d_c
@@ -521,7 +534,8 @@
 #define vpx_sad4x4 vpx_sad4x4_neon
 
 unsigned int vpx_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x4_avg vpx_sad4x4_avg_c
+unsigned int vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x4_avg vpx_sad4x4_avg_neon
 
 void vpx_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
@@ -533,10 +547,12 @@
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
 
 unsigned int vpx_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad4x8 vpx_sad4x8_c
+unsigned int vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad4x8 vpx_sad4x8_neon
 
 unsigned int vpx_sad4x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x8_avg vpx_sad4x8_avg_c
+unsigned int vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
@@ -545,10 +561,12 @@
 #define vpx_sad4x8x8 vpx_sad4x8x8_c
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad64x32 vpx_sad64x32_c
+unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad64x32 vpx_sad64x32_neon
 
 unsigned int vpx_sad64x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x32_avg vpx_sad64x32_avg_c
+unsigned int vpx_sad64x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x32x4d vpx_sad64x32x4d_c
@@ -558,7 +576,8 @@
 #define vpx_sad64x64 vpx_sad64x64_neon
 
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x64_avg vpx_sad64x64_avg_c
+unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
 void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x3 vpx_sad64x64x3_c
@@ -575,7 +594,8 @@
 #define vpx_sad8x16 vpx_sad8x16_neon
 
 unsigned int vpx_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x16_avg vpx_sad8x16_avg_c
+unsigned int vpx_sad8x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x16_avg vpx_sad8x16_avg_neon
 
 void vpx_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
@@ -587,10 +607,12 @@
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
 
 unsigned int vpx_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad8x4 vpx_sad8x4_c
+unsigned int vpx_sad8x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad8x4 vpx_sad8x4_neon
 
 unsigned int vpx_sad8x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x4_avg vpx_sad8x4_avg_c
+unsigned int vpx_sad8x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
@@ -603,7 +625,8 @@
 #define vpx_sad8x8 vpx_sad8x8_neon
 
 unsigned int vpx_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x8_avg vpx_sad8x8_avg_c
+unsigned int vpx_sad8x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x8_avg vpx_sad8x8_avg_neon
 
 void vpx_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
index c52128f..b978840 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
@@ -218,24 +218,28 @@
 #define vpx_fdct16x16 vpx_fdct16x16_neon
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct16x16_1 vpx_fdct16x16_1_c
+void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct16x16_1 vpx_fdct16x16_1_neon
 
 void vpx_fdct32x32_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct32x32_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct32x32 vpx_fdct32x32_neon
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_1 vpx_fdct32x32_1_c
+void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_1 vpx_fdct32x32_1_neon
 
 void vpx_fdct32x32_rd_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_rd vpx_fdct32x32_rd_c
+void vpx_fdct32x32_rd_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_rd vpx_fdct32x32_rd_neon
 
 void vpx_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct4x4 vpx_fdct4x4_neon
 
 void vpx_fdct4x4_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct4x4_1 vpx_fdct4x4_1_c
+void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct4x4_1 vpx_fdct4x4_1_neon
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *output, int stride);
@@ -444,7 +448,8 @@
 #define vpx_sad16x16 vpx_sad16x16_neon
 
 unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x16_avg vpx_sad16x16_avg_c
+unsigned int vpx_sad16x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x16_avg vpx_sad16x16_avg_neon
 
 void vpx_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x16x3 vpx_sad16x16x3_c
@@ -457,10 +462,12 @@
 #define vpx_sad16x16x8 vpx_sad16x16x8_c
 
 unsigned int vpx_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad16x32 vpx_sad16x32_c
+unsigned int vpx_sad16x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad16x32 vpx_sad16x32_neon
 
 unsigned int vpx_sad16x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x32_avg vpx_sad16x32_avg_c
+unsigned int vpx_sad16x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x32x4d vpx_sad16x32x4d_c
@@ -470,7 +477,8 @@
 #define vpx_sad16x8 vpx_sad16x8_neon
 
 unsigned int vpx_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x8_avg vpx_sad16x8_avg_c
+unsigned int vpx_sad16x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x8_avg vpx_sad16x8_avg_neon
 
 void vpx_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
@@ -482,10 +490,12 @@
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
 
 unsigned int vpx_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x16 vpx_sad32x16_c
+unsigned int vpx_sad32x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x16 vpx_sad32x16_neon
 
 unsigned int vpx_sad32x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x16_avg vpx_sad32x16_avg_c
+unsigned int vpx_sad32x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x16x4d vpx_sad32x16x4d_c
@@ -495,7 +505,8 @@
 #define vpx_sad32x32 vpx_sad32x32_neon
 
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x32_avg vpx_sad32x32_avg_c
+unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
 void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x3 vpx_sad32x32x3_c
@@ -508,10 +519,12 @@
 #define vpx_sad32x32x8 vpx_sad32x32x8_c
 
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x64 vpx_sad32x64_c
+unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x64 vpx_sad32x64_neon
 
 unsigned int vpx_sad32x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x64_avg vpx_sad32x64_avg_c
+unsigned int vpx_sad32x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x64x4d vpx_sad32x64x4d_c
@@ -521,7 +534,8 @@
 #define vpx_sad4x4 vpx_sad4x4_neon
 
 unsigned int vpx_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x4_avg vpx_sad4x4_avg_c
+unsigned int vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x4_avg vpx_sad4x4_avg_neon
 
 void vpx_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
@@ -533,10 +547,12 @@
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
 
 unsigned int vpx_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad4x8 vpx_sad4x8_c
+unsigned int vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad4x8 vpx_sad4x8_neon
 
 unsigned int vpx_sad4x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x8_avg vpx_sad4x8_avg_c
+unsigned int vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
@@ -545,10 +561,12 @@
 #define vpx_sad4x8x8 vpx_sad4x8x8_c
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad64x32 vpx_sad64x32_c
+unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad64x32 vpx_sad64x32_neon
 
 unsigned int vpx_sad64x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x32_avg vpx_sad64x32_avg_c
+unsigned int vpx_sad64x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x32x4d vpx_sad64x32x4d_c
@@ -558,7 +576,8 @@
 #define vpx_sad64x64 vpx_sad64x64_neon
 
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x64_avg vpx_sad64x64_avg_c
+unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
 void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x3 vpx_sad64x64x3_c
@@ -575,7 +594,8 @@
 #define vpx_sad8x16 vpx_sad8x16_neon
 
 unsigned int vpx_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x16_avg vpx_sad8x16_avg_c
+unsigned int vpx_sad8x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x16_avg vpx_sad8x16_avg_neon
 
 void vpx_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
@@ -587,10 +607,12 @@
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
 
 unsigned int vpx_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad8x4 vpx_sad8x4_c
+unsigned int vpx_sad8x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad8x4 vpx_sad8x4_neon
 
 unsigned int vpx_sad8x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x4_avg vpx_sad8x4_avg_c
+unsigned int vpx_sad8x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
@@ -603,7 +625,8 @@
 #define vpx_sad8x8 vpx_sad8x8_neon
 
 unsigned int vpx_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x8_avg vpx_sad8x8_avg_c
+unsigned int vpx_sad8x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x8_avg vpx_sad8x8_avg_neon
 
 void vpx_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
index 2c0dc17..068a03a 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
@@ -218,24 +218,28 @@
 RTCD_EXTERN void (*vpx_fdct16x16)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct16x16_1 vpx_fdct16x16_1_c
+void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output, int stride);
+RTCD_EXTERN void (*vpx_fdct16x16_1)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct32x32_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct32x32_neon(const int16_t *input, tran_low_t *output, int stride);
 RTCD_EXTERN void (*vpx_fdct32x32)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_1 vpx_fdct32x32_1_c
+void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output, int stride);
+RTCD_EXTERN void (*vpx_fdct32x32_1)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct32x32_rd_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_rd vpx_fdct32x32_rd_c
+void vpx_fdct32x32_rd_neon(const int16_t *input, tran_low_t *output, int stride);
+RTCD_EXTERN void (*vpx_fdct32x32_rd)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *output, int stride);
 RTCD_EXTERN void (*vpx_fdct4x4)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct4x4_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct4x4_1 vpx_fdct4x4_1_c
+void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride);
+RTCD_EXTERN void (*vpx_fdct4x4_1)(const int16_t *input, tran_low_t *output, int stride);
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *output, int stride);
@@ -444,7 +448,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad16x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x16_avg vpx_sad16x16_avg_c
+unsigned int vpx_sad16x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad16x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x16x3 vpx_sad16x16x3_c
@@ -457,10 +462,12 @@
 #define vpx_sad16x16x8 vpx_sad16x16x8_c
 
 unsigned int vpx_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad16x32 vpx_sad16x32_c
+unsigned int vpx_sad16x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad16x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad16x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x32_avg vpx_sad16x32_avg_c
+unsigned int vpx_sad16x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad16x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x32x4d vpx_sad16x32x4d_c
@@ -470,7 +477,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad16x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x8_avg vpx_sad16x8_avg_c
+unsigned int vpx_sad16x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad16x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
@@ -482,10 +490,12 @@
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
 
 unsigned int vpx_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x16 vpx_sad32x16_c
+unsigned int vpx_sad32x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad32x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad32x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x16_avg vpx_sad32x16_avg_c
+unsigned int vpx_sad32x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad32x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x16x4d vpx_sad32x16x4d_c
@@ -495,7 +505,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad32x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x32_avg vpx_sad32x32_avg_c
+unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad32x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x3 vpx_sad32x32x3_c
@@ -508,10 +519,12 @@
 #define vpx_sad32x32x8 vpx_sad32x32x8_c
 
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x64 vpx_sad32x64_c
+unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad32x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad32x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x64_avg vpx_sad32x64_avg_c
+unsigned int vpx_sad32x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad32x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x64x4d vpx_sad32x64x4d_c
@@ -521,7 +534,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad4x4)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x4_avg vpx_sad4x4_avg_c
+unsigned int vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad4x4_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
@@ -533,10 +547,12 @@
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
 
 unsigned int vpx_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad4x8 vpx_sad4x8_c
+unsigned int vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad4x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad4x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x8_avg vpx_sad4x8_avg_c
+unsigned int vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad4x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
@@ -545,10 +561,12 @@
 #define vpx_sad4x8x8 vpx_sad4x8x8_c
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad64x32 vpx_sad64x32_c
+unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad64x32)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad64x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x32_avg vpx_sad64x32_avg_c
+unsigned int vpx_sad64x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad64x32_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x32x4d vpx_sad64x32x4d_c
@@ -558,7 +576,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad64x64)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x64_avg vpx_sad64x64_avg_c
+unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad64x64_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x3 vpx_sad64x64x3_c
@@ -575,7 +594,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad8x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x16_avg vpx_sad8x16_avg_c
+unsigned int vpx_sad8x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad8x16_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
@@ -587,10 +607,12 @@
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
 
 unsigned int vpx_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad8x4 vpx_sad8x4_c
+unsigned int vpx_sad8x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+RTCD_EXTERN unsigned int (*vpx_sad8x4)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad8x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x4_avg vpx_sad8x4_avg_c
+unsigned int vpx_sad8x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad8x4_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
@@ -603,7 +625,8 @@
 RTCD_EXTERN unsigned int (*vpx_sad8x8)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
 
 unsigned int vpx_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x8_avg vpx_sad8x8_avg_c
+unsigned int vpx_sad8x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+RTCD_EXTERN unsigned int (*vpx_sad8x8_avg)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
 
 void vpx_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
@@ -922,10 +945,18 @@
     if (flags & HAS_NEON) vpx_dc_top_predictor_8x8 = vpx_dc_top_predictor_8x8_neon;
     vpx_fdct16x16 = vpx_fdct16x16_c;
     if (flags & HAS_NEON) vpx_fdct16x16 = vpx_fdct16x16_neon;
+    vpx_fdct16x16_1 = vpx_fdct16x16_1_c;
+    if (flags & HAS_NEON) vpx_fdct16x16_1 = vpx_fdct16x16_1_neon;
     vpx_fdct32x32 = vpx_fdct32x32_c;
     if (flags & HAS_NEON) vpx_fdct32x32 = vpx_fdct32x32_neon;
+    vpx_fdct32x32_1 = vpx_fdct32x32_1_c;
+    if (flags & HAS_NEON) vpx_fdct32x32_1 = vpx_fdct32x32_1_neon;
+    vpx_fdct32x32_rd = vpx_fdct32x32_rd_c;
+    if (flags & HAS_NEON) vpx_fdct32x32_rd = vpx_fdct32x32_rd_neon;
     vpx_fdct4x4 = vpx_fdct4x4_c;
     if (flags & HAS_NEON) vpx_fdct4x4 = vpx_fdct4x4_neon;
+    vpx_fdct4x4_1 = vpx_fdct4x4_1_c;
+    if (flags & HAS_NEON) vpx_fdct4x4_1 = vpx_fdct4x4_1_neon;
     vpx_fdct8x8 = vpx_fdct8x8_c;
     if (flags & HAS_NEON) vpx_fdct8x8 = vpx_fdct8x8_neon;
     vpx_fdct8x8_1 = vpx_fdct8x8_1_c;
@@ -1014,24 +1045,62 @@
     if (flags & HAS_NEON) vpx_post_proc_down_and_across_mb_row = vpx_post_proc_down_and_across_mb_row_neon;
     vpx_sad16x16 = vpx_sad16x16_c;
     if (flags & HAS_NEON) vpx_sad16x16 = vpx_sad16x16_neon;
+    vpx_sad16x16_avg = vpx_sad16x16_avg_c;
+    if (flags & HAS_NEON) vpx_sad16x16_avg = vpx_sad16x16_avg_neon;
     vpx_sad16x16x4d = vpx_sad16x16x4d_c;
     if (flags & HAS_NEON) vpx_sad16x16x4d = vpx_sad16x16x4d_neon;
+    vpx_sad16x32 = vpx_sad16x32_c;
+    if (flags & HAS_NEON) vpx_sad16x32 = vpx_sad16x32_neon;
+    vpx_sad16x32_avg = vpx_sad16x32_avg_c;
+    if (flags & HAS_NEON) vpx_sad16x32_avg = vpx_sad16x32_avg_neon;
     vpx_sad16x8 = vpx_sad16x8_c;
     if (flags & HAS_NEON) vpx_sad16x8 = vpx_sad16x8_neon;
+    vpx_sad16x8_avg = vpx_sad16x8_avg_c;
+    if (flags & HAS_NEON) vpx_sad16x8_avg = vpx_sad16x8_avg_neon;
+    vpx_sad32x16 = vpx_sad32x16_c;
+    if (flags & HAS_NEON) vpx_sad32x16 = vpx_sad32x16_neon;
+    vpx_sad32x16_avg = vpx_sad32x16_avg_c;
+    if (flags & HAS_NEON) vpx_sad32x16_avg = vpx_sad32x16_avg_neon;
     vpx_sad32x32 = vpx_sad32x32_c;
     if (flags & HAS_NEON) vpx_sad32x32 = vpx_sad32x32_neon;
+    vpx_sad32x32_avg = vpx_sad32x32_avg_c;
+    if (flags & HAS_NEON) vpx_sad32x32_avg = vpx_sad32x32_avg_neon;
     vpx_sad32x32x4d = vpx_sad32x32x4d_c;
     if (flags & HAS_NEON) vpx_sad32x32x4d = vpx_sad32x32x4d_neon;
+    vpx_sad32x64 = vpx_sad32x64_c;
+    if (flags & HAS_NEON) vpx_sad32x64 = vpx_sad32x64_neon;
+    vpx_sad32x64_avg = vpx_sad32x64_avg_c;
+    if (flags & HAS_NEON) vpx_sad32x64_avg = vpx_sad32x64_avg_neon;
     vpx_sad4x4 = vpx_sad4x4_c;
     if (flags & HAS_NEON) vpx_sad4x4 = vpx_sad4x4_neon;
+    vpx_sad4x4_avg = vpx_sad4x4_avg_c;
+    if (flags & HAS_NEON) vpx_sad4x4_avg = vpx_sad4x4_avg_neon;
+    vpx_sad4x8 = vpx_sad4x8_c;
+    if (flags & HAS_NEON) vpx_sad4x8 = vpx_sad4x8_neon;
+    vpx_sad4x8_avg = vpx_sad4x8_avg_c;
+    if (flags & HAS_NEON) vpx_sad4x8_avg = vpx_sad4x8_avg_neon;
+    vpx_sad64x32 = vpx_sad64x32_c;
+    if (flags & HAS_NEON) vpx_sad64x32 = vpx_sad64x32_neon;
+    vpx_sad64x32_avg = vpx_sad64x32_avg_c;
+    if (flags & HAS_NEON) vpx_sad64x32_avg = vpx_sad64x32_avg_neon;
     vpx_sad64x64 = vpx_sad64x64_c;
     if (flags & HAS_NEON) vpx_sad64x64 = vpx_sad64x64_neon;
+    vpx_sad64x64_avg = vpx_sad64x64_avg_c;
+    if (flags & HAS_NEON) vpx_sad64x64_avg = vpx_sad64x64_avg_neon;
     vpx_sad64x64x4d = vpx_sad64x64x4d_c;
     if (flags & HAS_NEON) vpx_sad64x64x4d = vpx_sad64x64x4d_neon;
     vpx_sad8x16 = vpx_sad8x16_c;
     if (flags & HAS_NEON) vpx_sad8x16 = vpx_sad8x16_neon;
+    vpx_sad8x16_avg = vpx_sad8x16_avg_c;
+    if (flags & HAS_NEON) vpx_sad8x16_avg = vpx_sad8x16_avg_neon;
+    vpx_sad8x4 = vpx_sad8x4_c;
+    if (flags & HAS_NEON) vpx_sad8x4 = vpx_sad8x4_neon;
+    vpx_sad8x4_avg = vpx_sad8x4_avg_c;
+    if (flags & HAS_NEON) vpx_sad8x4_avg = vpx_sad8x4_avg_neon;
     vpx_sad8x8 = vpx_sad8x8_c;
     if (flags & HAS_NEON) vpx_sad8x8 = vpx_sad8x8_neon;
+    vpx_sad8x8_avg = vpx_sad8x8_avg_c;
+    if (flags & HAS_NEON) vpx_sad8x8_avg = vpx_sad8x8_avg_neon;
     vpx_satd = vpx_satd_c;
     if (flags & HAS_NEON) vpx_satd = vpx_satd_neon;
     vpx_sub_pixel_avg_variance16x16 = vpx_sub_pixel_avg_variance16x16_c;
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
index c52128f..b978840 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
@@ -218,24 +218,28 @@
 #define vpx_fdct16x16 vpx_fdct16x16_neon
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct16x16_1 vpx_fdct16x16_1_c
+void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct16x16_1 vpx_fdct16x16_1_neon
 
 void vpx_fdct32x32_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct32x32_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct32x32 vpx_fdct32x32_neon
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_1 vpx_fdct32x32_1_c
+void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_1 vpx_fdct32x32_1_neon
 
 void vpx_fdct32x32_rd_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_rd vpx_fdct32x32_rd_c
+void vpx_fdct32x32_rd_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_rd vpx_fdct32x32_rd_neon
 
 void vpx_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct4x4 vpx_fdct4x4_neon
 
 void vpx_fdct4x4_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct4x4_1 vpx_fdct4x4_1_c
+void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct4x4_1 vpx_fdct4x4_1_neon
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *output, int stride);
@@ -444,7 +448,8 @@
 #define vpx_sad16x16 vpx_sad16x16_neon
 
 unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x16_avg vpx_sad16x16_avg_c
+unsigned int vpx_sad16x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x16_avg vpx_sad16x16_avg_neon
 
 void vpx_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x16x3 vpx_sad16x16x3_c
@@ -457,10 +462,12 @@
 #define vpx_sad16x16x8 vpx_sad16x16x8_c
 
 unsigned int vpx_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad16x32 vpx_sad16x32_c
+unsigned int vpx_sad16x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad16x32 vpx_sad16x32_neon
 
 unsigned int vpx_sad16x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x32_avg vpx_sad16x32_avg_c
+unsigned int vpx_sad16x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x32x4d vpx_sad16x32x4d_c
@@ -470,7 +477,8 @@
 #define vpx_sad16x8 vpx_sad16x8_neon
 
 unsigned int vpx_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x8_avg vpx_sad16x8_avg_c
+unsigned int vpx_sad16x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x8_avg vpx_sad16x8_avg_neon
 
 void vpx_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
@@ -482,10 +490,12 @@
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
 
 unsigned int vpx_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x16 vpx_sad32x16_c
+unsigned int vpx_sad32x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x16 vpx_sad32x16_neon
 
 unsigned int vpx_sad32x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x16_avg vpx_sad32x16_avg_c
+unsigned int vpx_sad32x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x16x4d vpx_sad32x16x4d_c
@@ -495,7 +505,8 @@
 #define vpx_sad32x32 vpx_sad32x32_neon
 
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x32_avg vpx_sad32x32_avg_c
+unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
 void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x3 vpx_sad32x32x3_c
@@ -508,10 +519,12 @@
 #define vpx_sad32x32x8 vpx_sad32x32x8_c
 
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x64 vpx_sad32x64_c
+unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x64 vpx_sad32x64_neon
 
 unsigned int vpx_sad32x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x64_avg vpx_sad32x64_avg_c
+unsigned int vpx_sad32x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x64x4d vpx_sad32x64x4d_c
@@ -521,7 +534,8 @@
 #define vpx_sad4x4 vpx_sad4x4_neon
 
 unsigned int vpx_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x4_avg vpx_sad4x4_avg_c
+unsigned int vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x4_avg vpx_sad4x4_avg_neon
 
 void vpx_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
@@ -533,10 +547,12 @@
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
 
 unsigned int vpx_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad4x8 vpx_sad4x8_c
+unsigned int vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad4x8 vpx_sad4x8_neon
 
 unsigned int vpx_sad4x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x8_avg vpx_sad4x8_avg_c
+unsigned int vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
@@ -545,10 +561,12 @@
 #define vpx_sad4x8x8 vpx_sad4x8x8_c
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad64x32 vpx_sad64x32_c
+unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad64x32 vpx_sad64x32_neon
 
 unsigned int vpx_sad64x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x32_avg vpx_sad64x32_avg_c
+unsigned int vpx_sad64x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x32x4d vpx_sad64x32x4d_c
@@ -558,7 +576,8 @@
 #define vpx_sad64x64 vpx_sad64x64_neon
 
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x64_avg vpx_sad64x64_avg_c
+unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
 void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x3 vpx_sad64x64x3_c
@@ -575,7 +594,8 @@
 #define vpx_sad8x16 vpx_sad8x16_neon
 
 unsigned int vpx_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x16_avg vpx_sad8x16_avg_c
+unsigned int vpx_sad8x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x16_avg vpx_sad8x16_avg_neon
 
 void vpx_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
@@ -587,10 +607,12 @@
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
 
 unsigned int vpx_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad8x4 vpx_sad8x4_c
+unsigned int vpx_sad8x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad8x4 vpx_sad8x4_neon
 
 unsigned int vpx_sad8x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x4_avg vpx_sad8x4_avg_c
+unsigned int vpx_sad8x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
@@ -603,7 +625,8 @@
 #define vpx_sad8x8 vpx_sad8x8_neon
 
 unsigned int vpx_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x8_avg vpx_sad8x8_avg_c
+unsigned int vpx_sad8x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x8_avg vpx_sad8x8_avg_neon
 
 void vpx_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
index c52128f..b978840 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
@@ -218,24 +218,28 @@
 #define vpx_fdct16x16 vpx_fdct16x16_neon
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct16x16_1 vpx_fdct16x16_1_c
+void vpx_fdct16x16_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct16x16_1 vpx_fdct16x16_1_neon
 
 void vpx_fdct32x32_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct32x32_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct32x32 vpx_fdct32x32_neon
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_1 vpx_fdct32x32_1_c
+void vpx_fdct32x32_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_1 vpx_fdct32x32_1_neon
 
 void vpx_fdct32x32_rd_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct32x32_rd vpx_fdct32x32_rd_c
+void vpx_fdct32x32_rd_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct32x32_rd vpx_fdct32x32_rd_neon
 
 void vpx_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct4x4_neon(const int16_t *input, tran_low_t *output, int stride);
 #define vpx_fdct4x4 vpx_fdct4x4_neon
 
 void vpx_fdct4x4_1_c(const int16_t *input, tran_low_t *output, int stride);
-#define vpx_fdct4x4_1 vpx_fdct4x4_1_c
+void vpx_fdct4x4_1_neon(const int16_t *input, tran_low_t *output, int stride);
+#define vpx_fdct4x4_1 vpx_fdct4x4_1_neon
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *output, int stride);
 void vpx_fdct8x8_neon(const int16_t *input, tran_low_t *output, int stride);
@@ -444,7 +448,8 @@
 #define vpx_sad16x16 vpx_sad16x16_neon
 
 unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x16_avg vpx_sad16x16_avg_c
+unsigned int vpx_sad16x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x16_avg vpx_sad16x16_avg_neon
 
 void vpx_sad16x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x16x3 vpx_sad16x16x3_c
@@ -457,10 +462,12 @@
 #define vpx_sad16x16x8 vpx_sad16x16x8_c
 
 unsigned int vpx_sad16x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad16x32 vpx_sad16x32_c
+unsigned int vpx_sad16x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad16x32 vpx_sad16x32_neon
 
 unsigned int vpx_sad16x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x32_avg vpx_sad16x32_avg_c
+unsigned int vpx_sad16x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x32_avg vpx_sad16x32_avg_neon
 
 void vpx_sad16x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x32x4d vpx_sad16x32x4d_c
@@ -470,7 +477,8 @@
 #define vpx_sad16x8 vpx_sad16x8_neon
 
 unsigned int vpx_sad16x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad16x8_avg vpx_sad16x8_avg_c
+unsigned int vpx_sad16x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad16x8_avg vpx_sad16x8_avg_neon
 
 void vpx_sad16x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad16x8x3 vpx_sad16x8x3_c
@@ -482,10 +490,12 @@
 #define vpx_sad16x8x8 vpx_sad16x8x8_c
 
 unsigned int vpx_sad32x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x16 vpx_sad32x16_c
+unsigned int vpx_sad32x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x16 vpx_sad32x16_neon
 
 unsigned int vpx_sad32x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x16_avg vpx_sad32x16_avg_c
+unsigned int vpx_sad32x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x16_avg vpx_sad32x16_avg_neon
 
 void vpx_sad32x16x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x16x4d vpx_sad32x16x4d_c
@@ -495,7 +505,8 @@
 #define vpx_sad32x32 vpx_sad32x32_neon
 
 unsigned int vpx_sad32x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x32_avg vpx_sad32x32_avg_c
+unsigned int vpx_sad32x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x32_avg vpx_sad32x32_avg_neon
 
 void vpx_sad32x32x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x32x3 vpx_sad32x32x3_c
@@ -508,10 +519,12 @@
 #define vpx_sad32x32x8 vpx_sad32x32x8_c
 
 unsigned int vpx_sad32x64_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad32x64 vpx_sad32x64_c
+unsigned int vpx_sad32x64_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad32x64 vpx_sad32x64_neon
 
 unsigned int vpx_sad32x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad32x64_avg vpx_sad32x64_avg_c
+unsigned int vpx_sad32x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad32x64_avg vpx_sad32x64_avg_neon
 
 void vpx_sad32x64x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad32x64x4d vpx_sad32x64x4d_c
@@ -521,7 +534,8 @@
 #define vpx_sad4x4 vpx_sad4x4_neon
 
 unsigned int vpx_sad4x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x4_avg vpx_sad4x4_avg_c
+unsigned int vpx_sad4x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x4_avg vpx_sad4x4_avg_neon
 
 void vpx_sad4x4x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x4x3 vpx_sad4x4x3_c
@@ -533,10 +547,12 @@
 #define vpx_sad4x4x8 vpx_sad4x4x8_c
 
 unsigned int vpx_sad4x8_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad4x8 vpx_sad4x8_c
+unsigned int vpx_sad4x8_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad4x8 vpx_sad4x8_neon
 
 unsigned int vpx_sad4x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad4x8_avg vpx_sad4x8_avg_c
+unsigned int vpx_sad4x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad4x8_avg vpx_sad4x8_avg_neon
 
 void vpx_sad4x8x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad4x8x4d vpx_sad4x8x4d_c
@@ -545,10 +561,12 @@
 #define vpx_sad4x8x8 vpx_sad4x8x8_c
 
 unsigned int vpx_sad64x32_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad64x32 vpx_sad64x32_c
+unsigned int vpx_sad64x32_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad64x32 vpx_sad64x32_neon
 
 unsigned int vpx_sad64x32_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x32_avg vpx_sad64x32_avg_c
+unsigned int vpx_sad64x32_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x32_avg vpx_sad64x32_avg_neon
 
 void vpx_sad64x32x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x32x4d vpx_sad64x32x4d_c
@@ -558,7 +576,8 @@
 #define vpx_sad64x64 vpx_sad64x64_neon
 
 unsigned int vpx_sad64x64_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad64x64_avg vpx_sad64x64_avg_c
+unsigned int vpx_sad64x64_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad64x64_avg vpx_sad64x64_avg_neon
 
 void vpx_sad64x64x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad64x64x3 vpx_sad64x64x3_c
@@ -575,7 +594,8 @@
 #define vpx_sad8x16 vpx_sad8x16_neon
 
 unsigned int vpx_sad8x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x16_avg vpx_sad8x16_avg_c
+unsigned int vpx_sad8x16_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x16_avg vpx_sad8x16_avg_neon
 
 void vpx_sad8x16x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x16x3 vpx_sad8x16x3_c
@@ -587,10 +607,12 @@
 #define vpx_sad8x16x8 vpx_sad8x16x8_c
 
 unsigned int vpx_sad8x4_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
-#define vpx_sad8x4 vpx_sad8x4_c
+unsigned int vpx_sad8x4_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride);
+#define vpx_sad8x4 vpx_sad8x4_neon
 
 unsigned int vpx_sad8x4_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x4_avg vpx_sad8x4_avg_c
+unsigned int vpx_sad8x4_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x4_avg vpx_sad8x4_avg_neon
 
 void vpx_sad8x4x4d_c(const uint8_t *src_ptr, int src_stride, const uint8_t * const ref_ptr[], int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x4x4d vpx_sad8x4x4d_c
@@ -603,7 +625,8 @@
 #define vpx_sad8x8 vpx_sad8x8_neon
 
 unsigned int vpx_sad8x8_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
-#define vpx_sad8x8_avg vpx_sad8x8_avg_c
+unsigned int vpx_sad8x8_avg_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred);
+#define vpx_sad8x8_avg vpx_sad8x8_avg_neon
 
 void vpx_sad8x8x3_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, uint32_t *sad_array);
 #define vpx_sad8x8x3 vpx_sad8x8x3_c
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
index 726de30..71cbee6 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -1064,6 +1064,7 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1072,6 +1073,7 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -2426,10 +2428,12 @@
     if (flags & HAS_SSE2) vpx_highbd_idct4x4_1_add = vpx_highbd_idct4x4_1_add_sse2;
     vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
     vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_sse2;
     vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_c;
     if (flags & HAS_SSE2) vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_sse2;
     vpx_highbd_lpf_horizontal_16_dual = vpx_highbd_lpf_horizontal_16_dual_c;
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
index 9d1d4244..5c8ad21 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -1071,7 +1071,8 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_12_add vpx_highbd_idct8x8_12_add_sse2
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_1_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1079,7 +1080,8 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_64_add vpx_highbd_idct8x8_64_add_sse2
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 #define vpx_highbd_iwht4x4_16_add vpx_highbd_iwht4x4_16_add_c
@@ -2111,6 +2113,10 @@
     if (flags & HAS_AVX2) vpx_highbd_convolve_copy = vpx_highbd_convolve_copy_avx2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse2;
     if (flags & HAS_SSE4_1) vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse4_1;
+    vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
+    vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_idct32x32_135_add = vpx_idct32x32_1024_add_sse2;
     if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
     vpx_idct32x32_34_add = vpx_idct32x32_34_add_sse2;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
index 726de30..71cbee6 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -1064,6 +1064,7 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1072,6 +1073,7 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -2426,10 +2428,12 @@
     if (flags & HAS_SSE2) vpx_highbd_idct4x4_1_add = vpx_highbd_idct4x4_1_add_sse2;
     vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
     vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_sse2;
     vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_c;
     if (flags & HAS_SSE2) vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_sse2;
     vpx_highbd_lpf_horizontal_16_dual = vpx_highbd_lpf_horizontal_16_dual_c;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
index 9d1d4244..5c8ad21 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -1071,7 +1071,8 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_12_add vpx_highbd_idct8x8_12_add_sse2
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_1_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1079,7 +1080,8 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_64_add vpx_highbd_idct8x8_64_add_sse2
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 #define vpx_highbd_iwht4x4_16_add vpx_highbd_iwht4x4_16_add_c
@@ -2111,6 +2113,10 @@
     if (flags & HAS_AVX2) vpx_highbd_convolve_copy = vpx_highbd_convolve_copy_avx2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse2;
     if (flags & HAS_SSE4_1) vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse4_1;
+    vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
+    vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_idct32x32_135_add = vpx_idct32x32_1024_add_sse2;
     if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
     vpx_idct32x32_34_add = vpx_idct32x32_34_add_sse2;
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 8fa39d83..81ea8fb8 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "818-gec4afbf74"
+#define VERSION_EXTRA  "923-g4e16f7070"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-818-gec4afbf74"
-#define VERSION_STRING      " v1.6.1-818-gec4afbf74"
+#define VERSION_STRING_NOSP "v1.6.1-923-g4e16f7070"
+#define VERSION_STRING      " v1.6.1-923-g4e16f7070"
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
index 726de30..71cbee6 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -1064,6 +1064,7 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1072,6 +1073,7 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -2426,10 +2428,12 @@
     if (flags & HAS_SSE2) vpx_highbd_idct4x4_1_add = vpx_highbd_idct4x4_1_add_sse2;
     vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
     vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_1_add = vpx_highbd_idct8x8_1_add_sse2;
     vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_c;
     if (flags & HAS_SSE2) vpx_highbd_lpf_horizontal_16 = vpx_highbd_lpf_horizontal_16_sse2;
     vpx_highbd_lpf_horizontal_16_dual = vpx_highbd_lpf_horizontal_16_dual_c;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
index 9d1d4244..5c8ad21 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -1071,7 +1071,8 @@
 
 void vpx_highbd_idct8x8_12_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_12_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_12_add vpx_highbd_idct8x8_12_add_sse2
+void vpx_highbd_idct8x8_12_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_12_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_idct8x8_1_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_1_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
@@ -1079,7 +1080,8 @@
 
 void vpx_highbd_idct8x8_64_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 void vpx_highbd_idct8x8_64_add_sse2(const tran_low_t *input, uint16_t *dest, int stride, int bd);
-#define vpx_highbd_idct8x8_64_add vpx_highbd_idct8x8_64_add_sse2
+void vpx_highbd_idct8x8_64_add_sse4_1(const tran_low_t *input, uint16_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct8x8_64_add)(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 
 void vpx_highbd_iwht4x4_16_add_c(const tran_low_t *input, uint16_t *dest, int stride, int bd);
 #define vpx_highbd_iwht4x4_16_add vpx_highbd_iwht4x4_16_add_c
@@ -2111,6 +2113,10 @@
     if (flags & HAS_AVX2) vpx_highbd_convolve_copy = vpx_highbd_convolve_copy_avx2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse2;
     if (flags & HAS_SSE4_1) vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_sse4_1;
+    vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_12_add = vpx_highbd_idct8x8_12_add_sse4_1;
+    vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse2;
+    if (flags & HAS_SSE4_1) vpx_highbd_idct8x8_64_add = vpx_highbd_idct8x8_64_add_sse4_1;
     vpx_idct32x32_135_add = vpx_idct32x32_1024_add_sse2;
     if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
     vpx_idct32x32_34_add = vpx_idct32x32_34_add_sse2;
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index bd9eea1..6cd032f 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -49,7 +49,7 @@
     "paper-radio-button": "PolymerElements/paper-radio-button#1.4.0",
     "paper-radio-group": "PolymerElements/paper-radio-group#1.2.0",
     "paper-ripple": "PolymerElements/paper-ripple#1.0.9",
-    "paper-slider": "PolymerElements/paper-slider#1.0.15",
+    "paper-slider": "PolymerElements/paper-slider#2.0.2",
     "paper-spinner": "PolymerElements/paper-spinner#1.2.0",
     "paper-styles": "PolymerElements/paper-styles#1.1.4",
     "paper-tabs": "PolymerElements/paper-tabs#1.6.2",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-slider/bower.json b/third_party/polymer/v1_0/components-chromium/paper-slider/bower.json
index 8062b3ce..90650495 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-slider/bower.json
+++ b/third_party/polymer/v1_0/components-chromium/paper-slider/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "paper-slider",
-  "version": "1.0.15",
+  "version": "2.0.2",
   "description": "A material design-style slider",
   "license": "http://polymer.github.io/LICENSE.txt",
   "authors": "The Polymer Authors",
@@ -17,22 +17,51 @@
   },
   "ignore": [],
   "dependencies": {
-    "polymer": "Polymer/polymer#^1.1.0",
-    "paper-input": "PolymerElements/paper-input#^1.0.0",
-    "paper-progress": "PolymerElements/paper-progress#^1.0.0",
-    "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
-    "paper-styles": "PolymerElements/paper-styles#^1.0.0",
-    "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
-    "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-    "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
-    "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0"
+    "polymer": "Polymer/polymer#1.9 - 2",
+    "paper-input": "PolymerElements/paper-input#1 - 2",
+    "paper-progress": "PolymerElements/paper-progress#1 - 2",
+    "iron-flex-layout": "PolymerElements/iron-flex-layout#1 - 2",
+    "paper-styles": "PolymerElements/paper-styles#1 - 2",
+    "iron-behaviors": "PolymerElements/iron-behaviors#1 - 2",
+    "paper-behaviors": "PolymerElements/paper-behaviors#1 - 2",
+    "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#1 - 2",
+    "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#1 - 2"
   },
   "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-    "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
-    "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-    "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
-    "web-component-tester": "^4.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+    "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
+    "iron-demo-helpers": "polymerelements/iron-demo-helpers#1 - 2",
+    "iron-test-helpers": "polymerelements/iron-test-helpers#1 - 2",
+    "test-fixture": "PolymerElements/test-fixture#^3.0.0-rc.1",
+    "web-component-tester": "^6.0.0",
+    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
+  },
+  "variants": {
+    "1.x": {
+      "dependencies": {
+        "polymer": "Polymer/polymer#^1.9",
+        "paper-input": "PolymerElements/paper-input#^1.0.0",
+        "paper-progress": "PolymerElements/paper-progress#^1.0.0",
+        "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
+        "paper-styles": "PolymerElements/paper-styles#^1.0.0",
+        "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
+        "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
+        "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
+        "iron-form-element-behavior": "PolymerElements/iron-form-element-behavior#^1.0.0"
+      },
+      "devDependencies": {
+        "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+        "iron-demo-helpers": "polymerelements/iron-demo-helpers#^1.0.0",
+        "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+        "iron-test-helpers": "polymerelements/iron-test-helpers#^1.0.0",
+        "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
+        "web-component-tester": "Polymer/web-component-tester#^4.0.0"
+      },
+      "resolutions": {
+        "webcomponentsjs": "^0.7"
+      }
+    }
+  },
+  "resolutions": {
+    "webcomponentsjs": "^1.0.0"
   }
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js
index d5f02d6..2e63d37 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js
+++ b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider-extracted.js
@@ -141,16 +141,16 @@
         this.setAttribute('aria-valuemax', max);
         this.setAttribute('aria-valuenow', value);
 
-        this._positionKnob(this._calcRatio(value));
+        this._positionKnob(this._calcRatio(value) * 100);
       },
 
       _valueChanged: function() {
-        this.fire('value-change');
+        this.fire('value-change', {composed: true});
       },
 
       _immediateValueChanged: function() {
         if (this.dragging) {
-          this.fire('immediate-value-change');
+          this.fire('immediate-value-change', {composed: true});
         } else {
           this.value = this.immediateValue;
         }
@@ -171,17 +171,17 @@
 
       _positionKnob: function(ratio) {
         this._setImmediateValue(this._calcStep(this._calcKnobPosition(ratio)));
-        this._setRatio(this._calcRatio(this.immediateValue));
+        this._setRatio(this._calcRatio(this.immediateValue) * 100);
 
-        this.$.sliderKnob.style.left = (this.ratio * 100) + '%';
+        this.$.sliderKnob.style.left = this.ratio + '%';
         if (this.dragging) {
-          this._knobstartx = this.ratio * this._w;
+          this._knobstartx = (this.ratio * this._w) / 100;
           this.translate3d(0, 0, 0, this.$.sliderKnob);
         }
       },
 
       _calcKnobPosition: function(ratio) {
-        return (this.max - this.min) * ratio + this.min;
+        return (this.max - this.min) * ratio / 100 + this.min;
       },
 
       _onTrack: function(event) {
@@ -200,8 +200,9 @@
       },
 
       _trackStart: function(event) {
+        this._setTransiting(false);
         this._w = this.$.sliderBar.offsetWidth;
-        this._x = this.ratio * this._w;
+        this._x = this.ratio * this._w / 100;
         this._startx = this._x;
         this._knobstartx = this._startx;
         this._minx = - this._startx;
@@ -220,7 +221,7 @@
             this._maxx, Math.max(this._minx, event.detail.dx * direction));
         this._x = this._startx + dx;
 
-        var immediateValue = this._calcStep(this._calcKnobPosition(this._x / this._w));
+        var immediateValue = this._calcStep(this._calcKnobPosition(this._x / this._w * 100));
         this._setImmediateValue(immediateValue);
 
         // update knob's position
@@ -238,7 +239,7 @@
 
         s.transform = s.webkitTransform = '';
 
-        this.fire('change');
+        this.fire('change', {composed: true});
       },
 
       _knobdown: function(event) {
@@ -254,9 +255,9 @@
       _bardown: function(event) {
         this._w = this.$.sliderBar.offsetWidth;
         var rect = this.$.sliderBar.getBoundingClientRect();
-        var ratio = (event.detail.x - rect.left) / this._w;
+        var ratio = (event.detail.x - rect.left) / this._w * 100;
         if (this._isRTL) {
-          ratio = 1 - ratio;
+          ratio = 100 - ratio;
         }
         var prevRatio = this.ratio;
 
@@ -275,7 +276,7 @@
         }
 
         this.async(function() {
-          this.fire('change');
+          this.fire('change', {composed: true});
         });
 
         // cancel selection
@@ -372,7 +373,7 @@
 
       _changeValue: function(event) {
         this.value = event.target.value;
-        this.fire('change');
+        this.fire('change', {composed: true});
       },
 
       _inputKeyDown: function(event) {
diff --git a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
index ab7e2dc7..364fb01 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
@@ -67,9 +67,9 @@
   <template strip-whitespace="">
     <style>
       :host {
-        @apply(--layout);
-        @apply(--layout-justified);
-        @apply(--layout-center);
+        @apply --layout;
+        @apply --layout-justified;
+        @apply --layout-center;
         width: 200px;
         cursor: default;
         -webkit-user-select: none;
@@ -77,10 +77,10 @@
         -ms-user-select: none;
         user-select: none;
         -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-        --paper-progress-active-color: var(--paper-slider-active-color, --google-blue-700);
-        --paper-progress-secondary-color: var(--paper-slider-secondary-color, --google-blue-300);
-        --paper-progress-disabled-active-color: var(--paper-slider-disabled-active-color, --paper-grey-400);
-        --paper-progress-disabled-secondary-color: var(--paper-slider-disabled-secondary-color, --paper-grey-400);
+        --paper-progress-active-color: var(--paper-slider-active-color, var(--google-blue-700));
+        --paper-progress-secondary-color: var(--paper-slider-secondary-color, var(--google-blue-300));
+        --paper-progress-disabled-active-color: var(--paper-slider-disabled-active-color, var(--paper-grey-400));
+        --paper-progress-disabled-secondary-color: var(--paper-slider-disabled-secondary-color, var(--paper-grey-400));
         --calculated-paper-slider-height: var(--paper-slider-height, 2px);
       }
 
@@ -88,12 +88,35 @@
       :host(:focus) {
         outline: none;
       }
-        
+
+      /** 
+       * NOTE(keanulee): Though :host-context is not universally supported, some pages
+       * still rely on paper-slider being flipped when dir="rtl" is set on body. For full
+       * compatability, dir="rtl" must be explicitly set on paper-slider.
+       */
       :host-context([dir="rtl"]) #sliderContainer {
         -webkit-transform: scaleX(-1);
         transform: scaleX(-1);
       }
 
+      /** 
+       * NOTE(keanulee): This is separate from the rule above because :host-context may
+       * not be recognized.
+       */
+      :host([dir="rtl"]) #sliderContainer {
+        -webkit-transform: scaleX(-1);
+        transform: scaleX(-1);
+      }
+
+      /** 
+       * NOTE(keanulee): Needed to override the :host-context rule (where supported)
+       * to support LTR sliders in RTL pages.
+       */
+      :host([dir="ltr"]) #sliderContainer {
+        -webkit-transform: scaleX(1);
+        transform: scaleX(1);
+      }
+
       #sliderContainer {
         position: relative;
         width: 100%;
@@ -137,7 +160,7 @@
         padding: 15px 0;
         width: 100%;
         background-color: var(--paper-slider-bar-color, transparent);
-        --paper-progress-container-color: var(--paper-slider-container-color, --paper-grey-400);
+        --paper-progress-container-color: var(--paper-slider-container-color, var(--paper-grey-400));
         --paper-progress-height: var(--calculated-paper-slider-height);
       }
 
@@ -149,11 +172,11 @@
         right: -1px;
         box-sizing: border-box;
         pointer-events: none;
-        @apply(--layout-horizontal);
+        @apply --layout-horizontal;
       }
 
       .slider-marker {
-        @apply(--layout-flex);
+        @apply --layout-flex;
       }
       .slider-markers::after,
       .slider-marker::after {
@@ -196,8 +219,8 @@
         margin: 10px;
         width: calc(100% - 20px);
         height: calc(100% - 20px);
-        background-color: var(--paper-slider-knob-color, --google-blue-700);
-        border: 2px solid var(--paper-slider-knob-color, --google-blue-700);
+        background-color: var(--paper-slider-knob-color, var(--google-blue-700));
+        border: 2px solid var(--paper-slider-knob-color, var(--google-blue-700));
         border-radius: 50%;
 
         -moz-box-sizing: border-box;
@@ -216,11 +239,11 @@
 
       .ring > .slider-knob > .slider-knob-inner {
         background-color: var(--paper-slider-knob-start-color, transparent);
-        border: 2px solid var(--paper-slider-knob-start-border-color, --paper-grey-400);
+        border: 2px solid var(--paper-slider-knob-start-border-color, var(--paper-grey-400));
       }
 
       .slider-knob-inner::before {
-        background-color: var(--paper-slider-pin-color, --google-blue-700);
+        background-color: var(--paper-slider-pin-color, var(--google-blue-700));
       }
 
       .pin > .slider-knob > .slider-knob-inner::before {
@@ -244,7 +267,7 @@
       }
 
       .pin.ring > .slider-knob > .slider-knob-inner::before {
-        background-color: var(--paper-slider-pin-start-color, --paper-grey-400);
+        background-color: var(--paper-slider-pin-start-color, var(--paper-grey-400));
       }
 
       .pin.expand > .slider-knob > .slider-knob-inner::before {
@@ -280,7 +303,7 @@
         --paper-input-container-input: {
           text-align: center;
         };
-        @apply(--paper-slider-input);
+        @apply --paper-slider-input;
       }
 
       /* disabled state */
@@ -289,19 +312,19 @@
       }
 
       .disabled > .slider-knob > .slider-knob-inner {
-        background-color: var(--paper-slider-disabled-knob-color, --paper-grey-400);
-        border: 2px solid var(--paper-slider-disabled-knob-color, --paper-grey-400);
+        background-color: var(--paper-slider-disabled-knob-color, var(--paper-grey-400));
+        border: 2px solid var(--paper-slider-disabled-knob-color, var(--paper-grey-400));
         -webkit-transform: scale3d(0.75, 0.75, 1);
         transform: scale3d(0.75, 0.75, 1);
       }
 
       .disabled.ring > .slider-knob > .slider-knob-inner {
         background-color: var(--paper-slider-knob-start-color, transparent);
-        border: 2px solid var(--paper-slider-knob-start-border-color, --paper-grey-400);
+        border: 2px solid var(--paper-slider-knob-start-border-color, var(--paper-grey-400));
       }
 
       paper-ripple {
-        color: var(--paper-slider-knob-color, --google-blue-700);
+        color: var(--paper-slider-knob-color, var(--google-blue-700));
       }
     </style>
 
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt
index e63da14..b64ac55 100644
--- a/third_party/polymer/v1_0/components_summary.txt
+++ b/third_party/polymer/v1_0/components_summary.txt
@@ -282,9 +282,9 @@
 
 Name: paper-slider
 Repository: https://github.com/PolymerElements/paper-slider.git
-Tree: v1.0.15
-Revision: b678296daa93526adc8bf4b75628a7a5759bdeea
-Tree link: https://github.com/PolymerElements/paper-slider/tree/v1.0.15
+Tree: v2.0.2
+Revision: 2abcf4052ce04ad450b06f6800f11055cb26ce5b
+Tree link: https://github.com/PolymerElements/paper-slider/tree/v2.0.2
 
 Name: paper-spinner
 Repository: https://github.com/PolymerElements/paper-spinner.git
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index 46e26a7..64056b0b 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1136,8 +1136,8 @@
 #endif
 
 template <>
-struct FuzzTraits<IPC::Message> {
-  static bool Fuzz(IPC::Message* p, Fuzzer* fuzzer) {
+struct FuzzTraits<std::unique_ptr<IPC::Message>> {
+  static bool Fuzz(std::unique_ptr<IPC::Message>* p, Fuzzer* fuzzer) {
     // TODO(mbarbella): Support mutation.
     if (!fuzzer->ShouldGenerate())
       return true;
@@ -1145,10 +1145,11 @@
     if (g_function_vector.empty())
       return false;
     size_t index = RandInRange(g_function_vector.size());
-    IPC::Message* ipc_message = (*g_function_vector[index])(NULL, fuzzer);
+    std::unique_ptr<IPC::Message> ipc_message =
+        (*g_function_vector[index])(nullptr, fuzzer);
     if (!ipc_message)
       return false;
-    p = ipc_message;
+    *p = std::move(ipc_message);
     return true;
   }
 };
@@ -1734,8 +1735,8 @@
 class MessageFactory<Message, IPC::MessageKind::CONTROL> {
  public:
   template <typename... Args>
-  static Message* New(const Args&... args) {
-    return new Message(args...);
+  static std::unique_ptr<Message> New(const Args&... args) {
+    return base::MakeUnique<Message>(args...);
   }
 };
 
@@ -1743,8 +1744,8 @@
 class MessageFactory<Message, IPC::MessageKind::ROUTED> {
  public:
   template <typename... Args>
-  static Message* New(const Args&... args) {
-    return new Message(RandInRange(MAX_FAKE_ROUTING_ID), args...);
+  static std::unique_ptr<Message> New(const Args&... args) {
+    return base::MakeUnique<Message>(RandInRange(MAX_FAKE_ROUTING_ID), args...);
   }
 };
 
@@ -1756,15 +1757,15 @@
  public:
   using Message = IPC::MessageT<Meta, std::tuple<Ins...>, void>;
 
-  static IPC::Message* Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
+  static std::unique_ptr<IPC::Message> Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
     return FuzzImpl(msg, fuzzer, base::MakeIndexSequence<sizeof...(Ins)>());
   }
 
  private:
   template <size_t... Ns>
-  static IPC::Message* FuzzImpl(IPC::Message* msg,
-                                Fuzzer* fuzzer,
-                                base::IndexSequence<Ns...>) {
+  static std::unique_ptr<IPC::Message> FuzzImpl(IPC::Message* msg,
+                                                Fuzzer* fuzzer,
+                                                base::IndexSequence<Ns...>) {
     typename Message::Param p;
     if (msg) {
       Message::Read(static_cast<Message*>(msg), &p);
@@ -1783,18 +1784,18 @@
  public:
   using Message = IPC::MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>;
 
-  static IPC::Message* Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
+  static std::unique_ptr<IPC::Message> Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
     return FuzzImpl(msg, fuzzer, base::MakeIndexSequence<sizeof...(Ins)>());
   }
 
  private:
   template <size_t... Ns>
-  static IPC::Message* FuzzImpl(IPC::Message* msg,
-                                Fuzzer* fuzzer,
-                                base::IndexSequence<Ns...>) {
+  static std::unique_ptr<IPC::Message> FuzzImpl(IPC::Message* msg,
+                                                Fuzzer* fuzzer,
+                                                base::IndexSequence<Ns...>) {
     typename Message::SendParam p;
     Message* real_msg = static_cast<Message*>(msg);
-    Message* new_msg = nullptr;
+    std::unique_ptr<Message> new_msg;
     if (real_msg) {
       Message::ReadSendParam(real_msg, &p);
     }
@@ -1803,7 +1804,7 @@
           std::get<Ns>(p)..., static_cast<Outs*>(nullptr)...);
     }
     if (real_msg && new_msg) {
-      MessageCracker::CopyMessageID(new_msg, real_msg);
+      MessageCracker::CopyMessageID(new_msg.get(), real_msg);
     } else if (!new_msg) {
       std::cerr << "Don't know how to handle " << Meta::kName << "\n";
     }
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.h b/tools/ipc_fuzzer/fuzzer/fuzzer.h
index f406a029..38bf58f2 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.h
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -67,16 +68,17 @@
   void FuzzBytes(void* data, int data_len) override {}
 };
 
-typedef IPC::Message* (*FuzzerFunction)(IPC::Message*, Fuzzer*);
+using FuzzerFunction = std::unique_ptr<IPC::Message> (*)(IPC::Message*,
+                                                         Fuzzer*);
 
 // Used for mutating messages. Once populated, the map associates a message ID
 // with a FuzzerFunction used for mutation of that message type.
-typedef base::hash_map<uint32_t, FuzzerFunction> FuzzerFunctionMap;
+using FuzzerFunctionMap = base::hash_map<uint32_t, FuzzerFunction>;
 void PopulateFuzzerFunctionMap(FuzzerFunctionMap* map);
 
 // Used for generating new messages. Once populated, the vector contains
 // FuzzerFunctions for all message types that we know how to generate.
-typedef std::vector<FuzzerFunction> FuzzerFunctionVector;
+using FuzzerFunctionVector = std::vector<FuzzerFunction>;
 void PopulateFuzzerFunctionVector(FuzzerFunctionVector* function_vector);
 
 // Since IPC::Message can be serialized, we also track a global function vector
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc b/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
index 04174af..a63dad5 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer_main.cc
@@ -7,6 +7,7 @@
 
 #include <iostream>
 #include <set>
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
@@ -93,10 +94,9 @@
   }
 };
 
-static IPC::Message* RewriteMessage(
-    IPC::Message* message,
-    Fuzzer* fuzzer,
-    FuzzerFunctionMap* map) {
+static std::unique_ptr<IPC::Message> RewriteMessage(IPC::Message* message,
+                                                    Fuzzer* fuzzer,
+                                                    FuzzerFunctionMap* map) {
   FuzzerFunctionMap::iterator it = map->find(message->type());
   if (it == map->end()) {
     // This usually indicates a missing message file in all_messages.h, or
@@ -128,8 +128,10 @@
   if (message_count < 0) {
     // Enumerate them all.
     for (size_t i = 0; i < g_function_vector.size(); ++i) {
-      if (IPC::Message* new_message = (*g_function_vector[i])(NULL, fuzzer))
-        message_vector.push_back(new_message);
+      std::unique_ptr<IPC::Message> new_message =
+          (*g_function_vector[i])(nullptr, fuzzer);
+      if (new_message)
+        message_vector.push_back(std::move(new_message));
       else
         bad_count += 1;
     }
@@ -137,8 +139,10 @@
     // Fuzz a random batch.
     for (int i = 0; i < message_count; ++i) {
       size_t index = RandInRange(g_function_vector.size());
-      if (IPC::Message* new_message = (*g_function_vector[index])(NULL, fuzzer))
-        message_vector.push_back(new_message);
+      std::unique_ptr<IPC::Message> new_message =
+          (*g_function_vector[index])(nullptr, fuzzer);
+      if (new_message)
+        message_vector.push_back(std::move(new_message));
       else
         bad_count += 1;
     }
@@ -177,19 +181,17 @@
     return EXIT_FAILURE;
 
   for (size_t i = 0; i < message_vector.size(); ++i) {
-    IPC::Message* msg = message_vector[i];
+    IPC::Message* msg = message_vector[i].get();
     // If an explicit type set is specified, make sure we should be mutating
     // this message type on this run.
     if (!type_set.empty() && type_set.end() == std::find(
             type_set.begin(), type_set.end(), msg->type())) {
       continue;
     }
-    IPC::Message* new_message = RewriteMessage(msg, fuzzer, &fuzz_function_map);
-    if (new_message) {
-      IPC::Message* old_message = message_vector[i];
-      delete old_message;
-      message_vector[i] = new_message;
-    }
+    std::unique_ptr<IPC::Message> new_message =
+        RewriteMessage(msg, fuzzer, &fuzz_function_map);
+    if (new_message)
+      message_vector[i] = std::move(new_message);
   }
 
   if (permute) {
diff --git a/tools/ipc_fuzzer/message_dump/message_dump.cc b/tools/ipc_fuzzer/message_dump/message_dump.cc
index 2c81545..bc650e7 100644
--- a/tools/ipc_fuzzer/message_dump/message_dump.cc
+++ b/tools/ipc_fuzzer/message_dump/message_dump.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
 #include "base/process/process.h"
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
@@ -31,7 +32,7 @@
   }
 
   IPC::Message* Rewrite(IPC::Message* message) override {
-    messages_.push_back(new IPC::Message(*message));
+    messages_.push_back(base::MakeUnique<IPC::Message>(*message));
     return message;
   }
 
diff --git a/tools/ipc_fuzzer/message_lib/message_file.h b/tools/ipc_fuzzer/message_lib/message_file.h
index 70ab55c..7afaa9b 100644
--- a/tools/ipc_fuzzer/message_lib/message_file.h
+++ b/tools/ipc_fuzzer/message_lib/message_file.h
@@ -5,14 +5,16 @@
 #ifndef TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_H_
 #define TOOLS_IPC_FUZZER_MESSAGE_LIB_MESSAGE_FILE_H_
 
+#include <memory>
+#include <vector>
+
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "ipc/ipc_message.h"
 
 namespace ipc_fuzzer {
 
-typedef ScopedVector<IPC::Message> MessageVector;
+using MessageVector = std::vector<std::unique_ptr<IPC::Message>>;
 
 class MessageFile {
  public:
diff --git a/tools/ipc_fuzzer/message_lib/message_file_reader.cc b/tools/ipc_fuzzer/message_lib/message_file_reader.cc
index b7cb05a8..e41f4f79 100644
--- a/tools/ipc_fuzzer/message_lib/message_file_reader.cc
+++ b/tools/ipc_fuzzer/message_lib/message_file_reader.cc
@@ -10,6 +10,7 @@
 #include "base/files/memory_mapped_file.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_piece.h"
 #include "ipc/ipc_message.h"
 #include "tools/ipc_fuzzer/message_lib/message_cracker.h"
@@ -127,8 +128,7 @@
 
     // Copy is necessary to fix message type later.
     IPC::Message const_message(begin, msglen);
-    IPC::Message* message = new IPC::Message(const_message);
-    messages_->push_back(message);
+    messages_->push_back(base::MakeUnique<IPC::Message>(const_message));
     file_data_.remove_prefix(msglen);
   }
   return true;
@@ -195,13 +195,12 @@
 // increase the lifetime of message files. This is only a partial fix because
 // message arguments and structure layouts can change as well.
 void Reader::FixMessageTypes() {
-  for (MessageVector::iterator it = messages_->begin();
-       it != messages_->end(); ++it) {
-    uint32_t type = (*it)->type();
+  for (const auto& message : *messages_) {
+    uint32_t type = message->type();
     const std::string& name = name_map_.TypeToName(type);
     uint32_t correct_type = MessageNames::GetInstance()->NameToType(name);
     if (type != correct_type)
-      MessageCracker::SetMessageType(*it, correct_type);
+      MessageCracker::SetMessageType(message.get(), correct_type);
   }
 }
 
diff --git a/tools/ipc_fuzzer/message_lib/message_file_writer.cc b/tools/ipc_fuzzer/message_lib/message_file_writer.cc
index 6511c27..2c1f23d 100644
--- a/tools/ipc_fuzzer/message_lib/message_file_writer.cc
+++ b/tools/ipc_fuzzer/message_lib/message_file_writer.cc
@@ -105,7 +105,7 @@
 
 bool Writer::WriteMessages() {
   for (size_t i = 0; i < messages_->size(); ++i) {
-    IPC::Message* message = (*messages_)[i];
+    IPC::Message* message = (*messages_)[i].get();
     if (!WriteBlob(message->data(), message->size()))
       return false;
   }
diff --git a/tools/ipc_fuzzer/message_replay/replay_process.cc b/tools/ipc_fuzzer/message_replay/replay_process.cc
index 325382e..1a862cd 100644
--- a/tools/ipc_fuzzer/message_replay/replay_process.cc
+++ b/tools/ipc_fuzzer/message_replay/replay_process.cc
@@ -5,7 +5,9 @@
 #include "tools/ipc_fuzzer/message_replay/replay_process.h"
 
 #include <limits.h>
+
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -129,11 +131,10 @@
     return;
   }
 
-  // Take next message and release it from vector.
-  IPC::Message* message = messages_[message_index_];
-  messages_[message_index_++] = NULL;
+  std::unique_ptr<IPC::Message> message =
+      std::move(messages_[message_index_++]);
 
-  if (!channel_->Send(message)) {
+  if (!channel_->Send(message.release())) {
     LOG(ERROR) << "ChannelProxy::Send() failed after "
                << message_index_ << " messages";
     base::MessageLoop::current()->QuitWhenIdle();
diff --git a/tools/ipc_fuzzer/message_tools/message_util.cc b/tools/ipc_fuzzer/message_tools/message_util.cc
index 1c74892..b598fa4 100644
--- a/tools/ipc_fuzzer/message_tools/message_util.cc
+++ b/tools/ipc_fuzzer/message_tools/message_util.cc
@@ -5,8 +5,11 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
+
 #include <iostream>
+#include <iterator>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
@@ -127,8 +130,8 @@
     if (!ipc_fuzzer::MessageFile::Read(base::FilePath(name), &message_vector))
       return EXIT_FAILURE;
     input_message_vector.insert(input_message_vector.end(),
-                                message_vector.begin(), message_vector.end());
-    message_vector.weak_clear();
+                                std::make_move_iterator(message_vector.begin()),
+                                std::make_move_iterator(message_vector.end()));
   }
 
   bool has_indices = cmd->HasSwitch(kInSwitch);
@@ -151,22 +154,21 @@
   for (size_t i = 0; i < input_message_vector.size(); ++i) {
     bool valid = (i >= start_index && i < end_index);
     if (valid && has_regexp) {
-      valid = MessageMatches(input_message_vector[i], filter_pattern);
+      valid = MessageMatches(input_message_vector[i].get(), filter_pattern);
     }
     if (valid && has_indices) {
       valid = indices[i];
     }
     if (valid != invert) {
-      output_message_vector.push_back(input_message_vector[i]);
+      output_message_vector.push_back(std::move(input_message_vector[i]));
       remap_vector.push_back(i);
-      input_message_vector[i] = NULL;
     }
   }
 
   if (perform_dump) {
     for (size_t i = 0; i < output_message_vector.size(); ++i) {
       std::cout << remap_vector[i] << ". "
-                << MessageName(output_message_vector[i]) << "\n";
+                << MessageName(output_message_vector[i].get()) << "\n";
     }
   } else {
     if (!ipc_fuzzer::MessageFile::Write(
diff --git a/tools/licenses.py b/tools/licenses.py
index 9f33ffb8..ee65177c 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -493,7 +493,7 @@
     third_party_deps = set()
     for build_dep in gn_deps.split():
         m = re.search(r'^(.+/third_party/[^/]+)/(.+/)?BUILD\.gn$', build_dep)
-        if m:
+        if m and not os.path.join('build', 'secondary') in build_dep:
             third_party_deps.add(m.group(1))
     return third_party_deps
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index fc2f227..fa38969 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -205,7 +205,7 @@
       'Mac deterministic': 'release_bot_mac_strip',
       'Mac deterministic (dbg)': 'debug_bot',
       'Mojo ChromiumOS': 'chromeos_with_codecs_ozone_release_trybot',
-      'Mojo Linux': 'release_bot',
+      'Mojo Linux': 'release_trybot',
       'Mojo Windows': 'release_bot_x86_minimal_symbols',
       'Ozone Linux': 'release_bot_ozone_linux',
       'Site Isolation Android': 'android_release_bot_minimal_symbols_arm64',
@@ -1777,7 +1777,7 @@
     },
 
     'mac_new_sdk': {
-      'gn_args': 'mac_sdk_min=10.12',
+      'gn_args': 'mac_sdk_min="10.12"',
     },
 
     'headless': {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 7633e42..0b4820b6 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -10657,10 +10657,30 @@
 </action>
 
 <action name="MobileOmniboxRefineSuggestion">
+  <obsolete>
+    Deprecated 07/2017. Replaced by MobileOmniboxRefineSuggestion.Query and
+    MobileOmniboxRefineSuggestion.Url.
+  </obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileOmniboxRefineSuggestion.Search">
+  <owner>jdonnelly@chromium.org</owner>
+  <description>
+    User used the refinement arrow in an omnibox search suggestion to copy the
+    text of the suggestion into the omnibox.
+  </description>
+</action>
+
+<action name="MobileOmniboxRefineSuggestion.Url">
+  <owner>jdonnelly@chromium.org</owner>
+  <description>
+    User used the refinement arrow in an omnibox URL suggestion to copy the text
+    of the suggestion into the omnibox.
+  </description>
+</action>
+
 <action name="MobileOmniboxSearch">
   <obsolete>
     Removed Sep 2016 because the name kept misleading people.  Replaced with
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index fe8f74b..c6eb84e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15765,6 +15765,7 @@
   <int value="2051" label="LinearAccelerationSensorConstructor"/>
   <int value="2052" label="ReportUriMultipleEndpoints"/>
   <int value="2053" label="ReportUriSingleEndpoint"/>
+  <int value="2054" label="V8ConstructorNonUndefinedPrimitiveReturn"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -22379,6 +22380,7 @@
   <int value="-2020024440" label="scroll-end-effect"/>
   <int value="-2017953534" label="enable-hosted-app-shim-creation"/>
   <int value="-2013551096" label="ViewsSimplifiedFullscreenUI:disabled"/>
+  <int value="-2012990889" label="SpannableInlineAutocomplete:enabled"/>
   <int value="-2009622663" label="WebRtcHWH264Encoding:enabled"/>
   <int value="-2008272679" label="disable-webrtc-hw-encoding"/>
   <int value="-2005089558" label="BackgroundVideoTrackOptimization:disabled"/>
@@ -22424,6 +22426,7 @@
   <int value="-1892555086" label="disable-compositor-animation-timelines"/>
   <int value="-1892000374" label="SeccompSandboxAndroid:enabled"/>
   <int value="-1888273969" label="tab-capture-upscale-quality"/>
+  <int value="-1887862464" label="SpannableInlineAutocomplete:disabled"/>
   <int value="-1887053262"
       label="enable-zero-suggest-most-visited-without-serp"/>
   <int value="-1882330924" label="NTPArticleSuggestions:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ccb12be..e4406dc4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -34601,6 +34601,15 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.SecureSchemeHasSSLStatus" enum="BooleanPresent">
+  <owner>jam@chromium.org</owner>
+  <summary>
+    True counts the events when a https URL commits with a SSL certificate.
+    False is when the certificate is missing. This should be at 100%, anything
+    less is probably a bug.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.Start.RendererBrowserDifference.Negative"
     units="ms">
   <obsolete>
@@ -81111,6 +81120,15 @@
   </summary>
 </histogram>
 
+<histogram name="UpdateClient.BackgroundDownloaderNewJob" enum="Boolean">
+  <owner>sorin@chromium.org</owner>
+  <summary>
+    True if a new BITS job was created to download the url, or false, if an
+    existing job was found in the BITS queue. The metric is recorded when
+    the component updater background downloader is asked to download a CRX.
+  </summary>
+</histogram>
+
 <histogram name="UpdateEngine.Attempt.ConnectionType"
     enum="UpdateEngineConnectionType">
   <owner>zeuthen@chromium.org</owner>
@@ -87841,6 +87859,9 @@
 </histogram>
 
 <histogram name="WinJumplist.DeleteDirectoryContentDuration" units="ms">
+  <obsolete>
+    Obsolete 07/06/2016 as we are no long recording this metric.
+  </obsolete>
   <owner>chengx@chromium.org</owner>
   <summary>Time spent in DeleteDirectoryContentAndLogRuntime().</summary>
 </histogram>
diff --git a/tools/perf/benchmarks/start_with_url.py b/tools/perf/benchmarks/start_with_url.py
index 4da8420..56d23c3 100644
--- a/tools/perf/benchmarks/start_with_url.py
+++ b/tools/perf/benchmarks/start_with_url.py
@@ -31,8 +31,6 @@
 
 
 @benchmark.Enabled('has tabs')
-@benchmark.Enabled('android')
-@benchmark.Disabled('chromeos', 'linux', 'mac', 'win')
 @benchmark.Owner(emails=['pasko@chromium.org'])
 class StartWithUrlColdTBM(_StartupPerfBenchmark):
   """Measures time to start Chrome cold with startup URLs."""
@@ -58,9 +56,6 @@
 
 
 @benchmark.Enabled('has tabs')
-@benchmark.Enabled('android')
-@benchmark.Disabled('android-reference')  # crbug.com/588786
-@benchmark.Disabled('chromeos', 'linux', 'mac', 'win')
 @benchmark.Owner(emails=['pasko@chromium.org'])
 class StartWithUrlWarmTBM(_StartupPerfBenchmark):
   """Measures stimetime to start Chrome warm with startup URLs."""
diff --git a/tools/perf/benchmarks/startup.py b/tools/perf/benchmarks/startup.py
index c1dbb09..8a80304 100644
--- a/tools/perf/benchmarks/startup.py
+++ b/tools/perf/benchmarks/startup.py
@@ -37,8 +37,6 @@
     return startup.Startup(cold=False)
 
 
-@benchmark.Disabled('snowleopard')  # crbug.com/336913
-@benchmark.Disabled('android')
 class StartupColdBlankPage(_StartupCold):
   """Measures cold startup time with a clean profile."""
   tag = 'cold'
@@ -51,11 +49,11 @@
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        pass # blank_page.html not disabled.
+        self.PermanentlyDisableBenchmark(
+            [story.expectations.ALL_ANDROID], 'Non Android benchmark')
     return StoryExpectations()
 
 
-@benchmark.Disabled('android')
 class StartupWarmBlankPage(_StartupWarm):
   """Measures warm startup time with a clean profile."""
   tag = 'warm'
@@ -65,12 +63,15 @@
   def Name(cls):
     return 'startup.warm.blank_page'
 
+  def GetExpectations(self):
+    class StoryExpectations(story.expectations.StoryExpectations):
+      def SetExpectations(self):
+        self.PermanentlyDisableBenchmark(
+            [story.expectations.ALL_ANDROID], 'Non Android benchmark')
+    return StoryExpectations()
 
-@benchmark.Disabled('reference',                   # http://crbug.com/476882
-                    'android',                     # http://crbug.com/481919
-                    'yosemite',                    # http://crbug.com/605485
-                    'mac',                         # http://crbug.com/700843
-                    'content-shell')               # No pregenerated profiles.
+
+@benchmark.Disabled('content-shell')  # No pregenerated profiles.
 class StartupLargeProfileColdBlankPage(_StartupCold):
   """Measures cold startup time with a large profile."""
   tag = 'cold'
@@ -94,12 +95,7 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('reference',                   # http://crbug.com/476882
-                    'android',                     # http://crbug.com/481919
-                    'yosemite',                    # http://crbug.com/605485
-                    'mac',                         # http://crbug.com/700843
-                    'win',                         # http://crbug.com/704137
-                    'content-shell')               # No pregenerated profiles.
+@benchmark.Disabled('content-shell')  # No pregenerated profiles.
 class StartupLargeProfileWarmBlankPage(_StartupWarm):
   """Measures warm startup time with a large profile."""
   tag = 'warm'
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index ad9b94ac..9978c171 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -50,5 +50,6 @@
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        pass # No tests disabled.
+        self.PermanentlyDisableBenchmark([story.expectations.ALL_MOBILE],
+                                         'Desktop benchmark.')
     return StoryExpectations()
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn
new file mode 100644
index 0000000..c3ee382
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -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.
+
+group("vr_perf_tests") {
+  testonly = true
+  data = [
+    "./__init__.py",
+    "./run_benchmark",
+    "./vr_config.py",
+    "benchmarks/",
+    "//chrome/android/shared_preference_files/test/",
+    "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+  ]
+  data_deps = [
+    "//chrome/android:vr_nfc_simulator_apk",
+  ]
+  deps = [
+    "//tools/perf:perf",
+  ]
+}
diff --git a/tools/perf/contrib/vr_benchmarks/__init__.py b/tools/perf/contrib/vr_benchmarks/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/__init__.py
diff --git a/tools/perf/contrib/vr_benchmarks/run_benchmark b/tools/perf/contrib/vr_benchmarks/run_benchmark
new file mode 100755
index 0000000..9c2ea23
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/run_benchmark
@@ -0,0 +1,59 @@
+#!/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 os
+import sys
+
+import vr_config
+
+sys.path.insert(1, vr_config.TELEMETRY_DIR)
+sys.path.append(vr_config.PYLIB_DIR)
+
+from pylib.constants import host_paths
+
+if host_paths.DEVIL_PATH not in sys.path:
+  sys.path.append(host_paths.DEVIL_PATH)
+
+from devil.android import device_utils
+from pylib.utils import shared_preference_utils
+from telemetry import benchmark_runner
+
+
+def main():
+  attached_devices = device_utils.DeviceUtils.HealthyDevices()
+  if len(attached_devices) == 0:
+    raise ValueError('No healthy devices attached')
+  if len(attached_devices) > 1:
+    raise NotImplementedError('Only one device currently supported, multiple '
+                              'found')
+  dev = attached_devices[0]
+
+  # Reinstall VrCore
+  # TODO(bsheedy): Change this to work if VrCore is still installed as a system
+  # app
+  dev.Install(os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party',
+                           'gvr-android-sdk', 'test-apks', 'vr_services',
+                           'vr_services_current.apk'))
+
+  # Install the NFC simulator APK
+  # TODO(bsheedy): Find a better way to get path to generated APK
+  dev.Install(os.path.join(host_paths.DIR_SOURCE_ROOT, 'out', 'Release',
+                           'apks', 'VrNfcSimulator.apk'))
+
+  # Setup VrCore
+  # TODO(bsheedy): Support different files to allow tests to be run on both
+  # Daydream ready and non-Daydream-ready devices
+  preferences = shared_preference_utils.ExtractSettingsFromJson(os.path.join(
+      host_paths.DIR_SOURCE_ROOT, 'chrome', 'android',
+      'shared_preference_files', 'test', 'vr_ddview_skipdon_setupcomplete.json'
+  ))
+  shared_preference_utils.ApplySharedPreferenceSettings(dev, preferences)
+
+  # Start the benchmarks
+  return benchmark_runner.main(vr_config.Config(['benchmarks']))
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/perf/contrib/vr_benchmarks/vr_config.py b/tools/perf/contrib/vr_benchmarks/vr_config.py
new file mode 100644
index 0000000..36fdf5e1
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/vr_config.py
@@ -0,0 +1,25 @@
+# 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
+
+# Add //tools/perf/ to system path
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
+
+from chrome_telemetry_build import chromium_config
+from core import path_util
+
+TELEMETRY_DIR = path_util.GetTelemetryDir()
+PYLIB_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                         '..', '..', '..', '..',
+                                         'build', 'android'))
+
+_top_level_dir = os.path.dirname(os.path.realpath(__file__))
+
+def Config(benchmark_subdirs):
+  return chromium_config.ChromiumConfig(
+      top_level_dir=_top_level_dir,
+      benchmark_dirs=[os.path.join(_top_level_dir, subdir)
+                      for subdir in benchmark_subdirs])
diff --git a/tools/perf/page_sets/startup_pages.py b/tools/perf/page_sets/startup_pages.py
index 9178aeb5..ee9799f 100644
--- a/tools/perf/page_sets/startup_pages.py
+++ b/tools/perf/page_sets/startup_pages.py
@@ -61,11 +61,15 @@
 # TODO(rnephew): Test if kapook.com fails on both or just one of the configs.
 class WarmStartupStoryExpectations(story.expectations.StoryExpectations):
   def SetExpectations(self):
+    self.PermanentlyDisableBenchmark(
+        [story.expectations.ALL_DESKTOP], 'Mobile benchmark')
     self.DisableStory(
         'http://kapook.com', [story.expectations.ALL], 'crbug.com/667470')
 
 
 class ColdStartupStoryExpectations(story.expectations.StoryExpectations):
   def SetExpectations(self):
+    self.PermanentlyDisableBenchmark(
+        [story.expectations.ALL_DESKTOP], 'Mobile benchmark')
     self.DisableStory(
         'http://kapook.com', [story.expectations.ALL], 'crbug.com/667470')
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
index fafb61796..9b32374a 100644
--- a/tools/perf/page_sets/system_health/expectations.py
+++ b/tools/perf/page_sets/system_health/expectations.py
@@ -21,9 +21,6 @@
                       'crbug.com/649392')
     self.DisableStory('play:media:pandora', [expectations.ALL],
                       'crbug.com/64939')
-    self.DisableStory('browse:tech:discourse_infinite_scroll',
-                      [expectations.ALL_WIN, expectations.ALL_LINUX],
-                      'crbug.com/728152')
     self.DisableStory('browse:news:cnn',
                       [expectations.ALL_MAC], 'crbug.com/728576')
 
@@ -47,9 +44,6 @@
                       'crbug.com/649392')
     self.DisableStory('play:media:pandora', [expectations.ALL],
                       'crbug.com/64939')
-    self.DisableStory('browse:tech:discourse_infinite_scroll',
-                      [expectations.ALL_WIN, expectations.ALL_LINUX],
-                      'crbug.com/728152')
     self.DisableStory('browse:news:cnn',
                       [expectations.ALL_MAC], 'crbug.com/728576')
     self.DisableStory('browse:social:twitter_infinite_scroll',
@@ -140,13 +134,8 @@
                       'crbug.com/712694')
     self.DisableStory('browse:tools:earth', [expectations.ALL],
                       'crbug.com/708590')
-    self.DisableStory('browse:tech:discourse_infinite_scroll',
-                      [expectations.ALL_WIN, expectations.ALL_LINUX],
-                      'crbug.com/728152')
     self.DisableStory('browse:news:cnn',
                       [expectations.ALL_MAC], 'crbug.com/728576')
-    self.DisableStory('browse:social:twitter_infinite_scroll',
-                      [expectations.ALL], 'crbug.com/728464')
 
 # Should only include browse:*:* stories.
 class V8BrowsingMobileExpecations(expectations.StoryExpectations):
diff --git a/tools/win/linker_verbose_tracking.py b/tools/win/linker_verbose_tracking.py
index 1b5736a..b92cc34 100644
--- a/tools/win/linker_verbose_tracking.py
+++ b/tools/win/linker_verbose_tracking.py
@@ -26,28 +26,44 @@
 to reference another. Removing or moving the problematic symbol can fix the
 problem. See crrev.com/2559063002 for an example of such a change.
 
+In some cases a target needs to be a source_set in component builds (so that all
+of its functions will be exported) but should be a static_library in
+non-component builds. The BUILD.gn pattern for that is:
+
+  if (is_component_build) {
+    link_target_type = "source_set"
+  } else {
+    link_target_type = "static_library"
+  }
+  target(link_target_type, "filters") {
+
 One complication is that there are sometimes multiple source files with the
-same name, such as crc.c, which can make analysis more difficult or
-ambiguous. If this becomes a blocking issue they it may be necessary to
-temporarily rename the source file.
+same name, such as mime_util.cc, all creating mime_util.obj. The script takes
+whatever search criteria you pass and looks for all .obj files that were loaded
+that contain that sub-string. It will print the search list that it will use
+before reporting on why all of these .obj files were loaded. For instance, the
+initial output if mime_util.obj is specified will be something like this:
+
+>python linker_verbose_tracking.py verbose.txt mime_util.obj
+  Searching for [u'net.lib(mime_util.obj)', u'base.lib(mime_util.obj)']
+
+If you want to restrict the search to just one of these .obj files then you can
+give a fully specified name, like this:
+
+>python linker_verbose_tracking.py verbose.txt base.lib(mime_util.obj)
 
 Object file name matching is case sensitive.
 
-Typical output when run on chrome.dll verbose link output is:
+Typical output when run on chrome_watcher.dll verbose link output is:
 
->python tools\win\linker_verbose_tracking.py chrome_verbose_02.txt flac_crc
-Database loaded - 11277 xrefs found
-flac_crc.obj pulled in for symbol "_FLAC__crc8" by
-        stream_decoder.obj
-        bitwriter.obj
+>python tools\win\linker_verbose_tracking.py verbose08.txt drop_data
+Database loaded - 3844 xrefs found
+Searching for common_sources.lib(drop_data.obj)
+common_sources.lib(drop_data.obj).obj pulled in for symbol Metadata::Metadata...
+        common.lib(content_message_generator.obj)
 
-stream_decoder.obj pulled in for symbol "_FLAC__stream_decoder_new" by
-        stream_encoder.obj
-bitwriter.obj pulled in for symbol "_FLAC__bitwriter_new" by
-        stream_encoder.obj
-
-stream_encoder.obj pulled in for symbol "_FLAC__stream_encoder_new" by
-        Command-line obj file: audio_encoder.obj
+common.lib(content_message_generator.obj).obj pulled in for symbol ...
+        Command-line obj file: url_loader.mojom.obj
 """
 
 import io
@@ -58,16 +74,26 @@
 def ParseVerbose(input_file):
   # This matches line like this:
   #   Referenced in skia.lib(SkError.obj)
-  # with the groups()[0] referring to the object file name without the file
-  # extension.
-  obj_match = re.compile('.*\((.*)\.obj\)')
-  # Prefix used for symbols that are referenced:
+  #   Referenced in cloud_print_helpers.obj
+  #   Loaded libvpx.lib(vp9_encodemb.obj)
+  # groups()[0] will be 'Referenced in ' or 'Loaded ' and groups()[1] will be
+  # the fully qualified object-file name (including the .lib name if present).
+  obj_match = re.compile('.*(Referenced in |Loaded )(.*)')
+
+  # Prefix used for symbols that are found and therefore loaded:
   found_prefix = '      Found'
 
+  # This dictionary is indexed by (fully specified) object file names and the
+  # payload is the list of object file names that caused the object file that
+  # is the key name to be pulled in.
   cross_refs = {}
+  # This dictionary has the same index as cross_refs but its payload is the
+  # simple that caused the object file to be pulled in.
   cross_refed_symbols = {}
 
+  # None or a list of .obj files that referenced a symbol.
   references = None
+
   # When you redirect the linker output to a file from a command prompt the
   # result will be a utf-8 (or ASCII?) output file. However if you do the same
   # thing from PowerShell you get a utf-16 file. So, we need to handle both
@@ -81,6 +107,8 @@
   with io.open(input_file, encoding=file_encoding) as file_handle:
     for line in file_handle:
       if line.startswith(found_prefix):
+        # Create a list to hold all of the references to this symbol which
+        # caused the linker to load it.
         references = []
         # Grab the symbol name
         symbol = line[len(found_prefix):].strip()
@@ -88,30 +116,32 @@
           # Strip off leading and trailing quotes if present.
           symbol = symbol[1:-1]
         continue
+      # If we are looking for references to a symbol...
       if type(references) == type([]):
         sub_line = line.strip()
         match = obj_match.match(sub_line)
-        # See if the line is part of the list of places where this symbol was
-        # referenced
-        if sub_line.count('Referenced ') > 0:
-          if match:
-            # This indicates a match that is xxx.lib(yyy.obj), so a referencing
-            # .obj file that was itself inside of a library. We discard the
-            # library name.
-            reference = match.groups()[0]
+        if match:
+          match_type, obj_name = match.groups()
+          # See if the line is part of the list of places where this symbol was
+          # referenced:
+          if match_type == 'Referenced in ':
+            if '.lib' in obj_name:
+              # This indicates a match that is xxx.lib(yyy.obj), so a
+              # referencing .obj file that was itself inside of a library.
+              reference = obj_name
+            else:
+              # This indicates a match that is just a pure .obj file name
+              # I think this means that the .obj file was specified on the
+              # linker command line.
+              reference = ('Command-line obj file: ' +
+                           obj_name)
+            references.append(reference)
           else:
-            # This indicates a match that is just a pure .obj file name
-            # I think this means that the .obj file was specified on the linker
-            # command line.
-            reference = ('Command-line obj file: ' +
-                         sub_line[len('Referenced in '): -len('.obj')])
-          references.append(reference)
-        elif sub_line.count('Loaded ') > 0:
-          if match:
-            loaded = match.groups()[0]
-            cross_refs[loaded] = references
-            cross_refed_symbols[loaded] = symbol
-          references = None
+            assert(match_type == 'Loaded ')
+            if '.lib' in obj_name and '.obj' in obj_name:
+              cross_refs[obj_name] = references
+              cross_refed_symbols[obj_name] = symbol
+            references = None
       if line.startswith('Finished pass 1'):
         # Stop now because the remaining 90% of the verbose output is
         # not of interest. Could probably use /VERBOSE:REF to trim out
@@ -121,15 +151,26 @@
 
 
 def TrackObj(cross_refs, cross_refed_symbols, obj_name):
-  if obj_name.lower().endswith('.obj'):
-    obj_name = obj_name[:-len('.obj')]
-
   # Keep track of which references we've already followed.
   tracked = {}
 
   # Initial set of object files that we are tracking.
-  targets = [obj_name]
+  targets = []
+  for key in cross_refs.keys():
+    # Look for any object files that were pulled in that contain the name
+    # passed on the command line.
+    if obj_name in key:
+      targets.append(key)
+  if len(targets) == 0:
+    targets.append(obj_name)
+  # Print what we are searching for.
+  if len(targets) == 1:
+    print 'Searching for %s' % targets[0]
+  else:
+    print 'Searching for %s' % targets
   printed = False
+  # Follow the chain of references up to an arbitrary maximum level, which has
+  # so far never been approached.
   for i in range(100):
     new_targets = {}
     for target in targets:
@@ -140,14 +181,14 @@
           printed = True
           print '%s.obj pulled in for symbol "%s" by' % (target, symbol)
           for ref in cross_refs[target]:
-            print '\t%s.obj' % ref
+            print '\t%s' % ref
             new_targets[ref] = True
     if len(new_targets) == 0:
       break
     print
     targets = new_targets.keys()
   if not printed:
-    print ('No references to %s.obj found. Directly specified in sources or a '
+    print ('No references to %s found. Directly specified in sources or a '
           'source_set?' % obj_name)
 
 
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc
index 0d7d03c..bf66431 100644
--- a/ui/accessibility/ax_role_properties.cc
+++ b/ui/accessibility/ax_role_properties.cc
@@ -84,4 +84,53 @@
   }
 }
 
+bool IsControl(ui::AXRole role) {
+  switch (role) {
+    case ui::AX_ROLE_BUTTON:
+    case ui::AX_ROLE_CHECK_BOX:
+    case ui::AX_ROLE_COLOR_WELL:
+    case ui::AX_ROLE_COMBO_BOX:
+    case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
+    case ui::AX_ROLE_LIST_BOX:
+    case ui::AX_ROLE_MENU:
+    case ui::AX_ROLE_MENU_BAR:
+    case ui::AX_ROLE_MENU_BUTTON:
+    case ui::AX_ROLE_MENU_ITEM:
+    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+    case ui::AX_ROLE_MENU_ITEM_RADIO:
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+    case ui::AX_ROLE_MENU_LIST_POPUP:
+    case ui::AX_ROLE_POP_UP_BUTTON:
+    case ui::AX_ROLE_RADIO_BUTTON:
+    case ui::AX_ROLE_SCROLL_BAR:
+    case ui::AX_ROLE_SEARCH_BOX:
+    case ui::AX_ROLE_SLIDER:
+    case ui::AX_ROLE_SPIN_BUTTON:
+    case ui::AX_ROLE_SWITCH:
+    case ui::AX_ROLE_TAB:
+    case ui::AX_ROLE_TEXT_FIELD:
+    case ui::AX_ROLE_TOGGLE_BUTTON:
+    case ui::AX_ROLE_TREE:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool IsMenuRelated(ui::AXRole role) {
+  switch (role) {
+    case ui::AX_ROLE_MENU:
+    case ui::AX_ROLE_MENU_BAR:
+    case ui::AX_ROLE_MENU_BUTTON:
+    case ui::AX_ROLE_MENU_ITEM:
+    case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+    case ui::AX_ROLE_MENU_ITEM_RADIO:
+    case ui::AX_ROLE_MENU_LIST_OPTION:
+    case ui::AX_ROLE_MENU_LIST_POPUP:
+      return true;
+    default:
+      return false;
+  }
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h
index 6ee8234..22c7c2b 100644
--- a/ui/accessibility/ax_role_properties.h
+++ b/ui/accessibility/ax_role_properties.h
@@ -26,6 +26,12 @@
 // Returns true if this node is a row container.
 AX_EXPORT bool IsRowContainer(ui::AXRole role);
 
+// Returns true if this node is a control.
+AX_EXPORT bool IsControl(ui::AXRole role);
+
+// Returns true if this node is a menu or related role.
+AX_EXPORT bool IsMenuRelated(ui::AXRole role);
+
 }  // namespace ui
 
 #endif  // UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 1d7d95d..295a404 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1362,10 +1362,10 @@
       return ROLE_SYSTEM_MENUITEM;
 
     case ui::AX_ROLE_MENU_LIST_POPUP:
-      return ROLE_SYSTEM_LIST;
+      return ROLE_SYSTEM_MENUPOPUP;
 
     case ui::AX_ROLE_MENU_LIST_OPTION:
-      return ROLE_SYSTEM_LISTITEM;
+      return ROLE_SYSTEM_MENUITEM;
 
     case ui::AX_ROLE_NAVIGATION:
       return ROLE_SYSTEM_GROUPING;
diff --git a/ui/app_list/app_list_features.cc b/ui/app_list/app_list_features.cc
index efb627a..55973ae 100644
--- a/ui/app_list/app_list_features.cc
+++ b/ui/app_list/app_list_features.cc
@@ -17,8 +17,8 @@
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableFullscreenAppList{"EnableFullscreenAppList",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kEnablePlaystoreAppSearch{
-    "EnablePlaystoreAppSearch", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kEnablePlayStoreAppSearch{
+    "EnablePlayStoreAppSearch", base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsAnswerCardEnabled() {
   static const bool enabled = base::FeatureList::IsEnabled(kEnableAnswerCard);
@@ -42,9 +42,9 @@
          (IsAnswerCardEnabled() && !IsAnswerCardDarkRunEnabled());
 }
 
-bool IsPlaystoreAppSearchEnabled() {
+bool IsPlayStoreAppSearchEnabled() {
   static const bool enabled =
-      base::FeatureList::IsEnabled(kEnablePlaystoreAppSearch);
+      base::FeatureList::IsEnabled(kEnablePlayStoreAppSearch);
   return enabled;
 }
 
diff --git a/ui/app_list/app_list_features.h b/ui/app_list/app_list_features.h
index 5c18718..245fe68 100644
--- a/ui/app_list/app_list_features.h
+++ b/ui/app_list/app_list_features.h
@@ -32,7 +32,7 @@
 bool APP_LIST_EXPORT IsAnswerCardDarkRunEnabled();
 bool APP_LIST_EXPORT IsFullscreenAppListEnabled();
 bool APP_LIST_EXPORT IsSearchResultsNewDesignEnabled();
-bool APP_LIST_EXPORT IsPlaystoreAppSearchEnabled();
+bool APP_LIST_EXPORT IsPlayStoreAppSearchEnabled();
 int APP_LIST_EXPORT AnswerCardMaxWidth();
 int APP_LIST_EXPORT AnswerCardMaxHeight();
 std::string APP_LIST_EXPORT AnswerServerUrl();
diff --git a/ui/app_list/test/run_all_unittests.cc b/ui/app_list/test/run_all_unittests.cc
index 21ec801..002be81 100644
--- a/ui/app_list/test/run_all_unittests.cc
+++ b/ui/app_list/test/run_all_unittests.cc
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/env.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/gl/test/gl_surface_test_support.h"
@@ -32,8 +33,9 @@
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(kTestType, "applist");
 
-    gl::GLSurfaceTestSupport::InitializeOneOff();
     base::TestSuite::Initialize();
+    gl::GLSurfaceTestSupport::InitializeOneOff();
+    env_ = aura::Env::CreateInstance();
     ui::RegisterPathProvider();
 
     base::FilePath ui_test_pak_path;
@@ -45,11 +47,13 @@
   }
 
   void Shutdown() override {
+    env_.reset();
     ui::ResourceBundle::CleanupSharedInstance();
     base::TestSuite::Shutdown();
   }
 
  private:
+  std::unique_ptr<aura::Env> env_;
   base::TestDiscardableMemoryAllocator discardable_memory_allocator_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListTestSuite);
diff --git a/ui/app_list/views/search_result_tile_item_list_view.cc b/ui/app_list/views/search_result_tile_item_list_view.cc
index 344db2a..ae0cba3 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.cc
+++ b/ui/app_list/views/search_result_tile_item_list_view.cc
@@ -45,8 +45,9 @@
     views::Textfield* search_box,
     AppListViewDelegate* view_delegate)
     : search_box_(search_box),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
-  if (is_fullscreen_app_list_enabled_) {
+      is_play_store_app_search_enabled_(
+          features::IsPlayStoreAppSearchEnabled()) {
+  if (is_play_store_app_search_enabled_) {
     SetLayoutManager(new views::BoxLayout(
         views::BoxLayout::kHorizontal,
         gfx::Insets(kItemListVerticalSpacing, kItemListHorizontalSpacing),
@@ -113,10 +114,10 @@
   std::vector<SearchResult*> display_results =
       AppListModel::FilterSearchResultsByDisplayType(
           results(), SearchResult::DISPLAY_TILE,
-          is_fullscreen_app_list_enabled_ ? kMaxNumSearchResultTiles
-                                          : kNumSearchResultTiles);
+          is_play_store_app_search_enabled_ ? kMaxNumSearchResultTiles
+                                            : kNumSearchResultTiles);
 
-  if (is_fullscreen_app_list_enabled_) {
+  if (is_play_store_app_search_enabled_) {
     SearchResult::ResultType previous_type = SearchResult::RESULT_UNKNOWN;
 
     for (size_t i = 0; i < kMaxNumSearchResultTiles; ++i) {
diff --git a/ui/app_list/views/search_result_tile_item_list_view.h b/ui/app_list/views/search_result_tile_item_list_view.h
index 2b306be..4ad4c601 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.h
+++ b/ui/app_list/views/search_result_tile_item_list_view.h
@@ -48,8 +48,8 @@
 
   views::Textfield* search_box_;  // Owned by the views hierarchy.
 
-  // Whether the fullscreen app list feature is enabled.
-  const bool is_fullscreen_app_list_enabled_;
+  // Whether the Play Store app search feature is enabled.
+  const bool is_play_store_app_search_enabled_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResultTileItemListView);
 };
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc
index fcb8eff4..b78dca4 100644
--- a/ui/app_list/views/search_result_tile_item_view.cc
+++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -43,12 +43,13 @@
     AppListViewDelegate* view_delegate)
     : result_container_(result_container),
       view_delegate_(view_delegate),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+      is_play_store_app_search_enabled_(
+          features::IsPlayStoreAppSearchEnabled()) {
   // When |item_| is null, the tile is invisible. Calling SetSearchResult with a
   // non-null item makes the tile visible.
   SetVisible(false);
 
-  if (is_fullscreen_app_list_enabled_) {
+  if (is_play_store_app_search_enabled_) {
     const gfx::FontList& base_font =
         ui::ResourceBundle::GetSharedInstance().GetFontList(
             ui::ResourceBundle::BaseFont);
@@ -106,7 +107,7 @@
   SetRating(item_->rating());
   SetPrice(item_->formatted_price());
 
-  if (is_fullscreen_app_list_enabled_) {
+  if (is_play_store_app_search_enabled_) {
     const gfx::FontList& base_font =
         ui::ResourceBundle::GetSharedInstance().GetFontList(
             ui::ResourceBundle::BaseFont);
@@ -230,7 +231,7 @@
   if (rect.IsEmpty())
     return;
 
-  if (!is_fullscreen_app_list_enabled_ || !item_) {
+  if (!is_play_store_app_search_enabled_ || !item_) {
     TileItemView::Layout();
     return;
   }
@@ -292,7 +293,7 @@
 }
 
 gfx::Size SearchResultTileItemView::CalculatePreferredSize() const {
-  if (is_fullscreen_app_list_enabled_ && item_) {
+  if (is_play_store_app_search_enabled_ && item_) {
     if (item_->display_type() == SearchResult::DISPLAY_RECOMMENDATION)
       return gfx::Size(kGridTileWidth, kGridTileHeight);
     if (item_->display_type() == SearchResult::DISPLAY_TILE)
diff --git a/ui/app_list/views/search_result_tile_item_view.h b/ui/app_list/views/search_result_tile_item_view.h
index 03404fe..407a4777 100644
--- a/ui/app_list/views/search_result_tile_item_view.h
+++ b/ui/app_list/views/search_result_tile_item_view.h
@@ -5,6 +5,8 @@
 #ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_VIEW_H_
 #define UI_APP_LIST_VIEWS_SEARCH_RESULT_TILE_ITEM_VIEW_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "ui/app_list/search_result_observer.h"
 #include "ui/app_list/views/tile_item_view.h"
@@ -73,7 +75,8 @@
 
   AppListViewDelegate* view_delegate_;
 
-  const bool is_fullscreen_app_list_enabled_;
+  // Whether the Play Store app search feature is enabled.
+  const bool is_play_store_app_search_enabled_;
 
   std::unique_ptr<views::MenuRunner> context_menu_runner_;
 
diff --git a/ui/app_list/views/tile_item_view.cc b/ui/app_list/views/tile_item_view.cc
index 5d5d98d..245e6cf 100644
--- a/ui/app_list/views/tile_item_view.cc
+++ b/ui/app_list/views/tile_item_view.cc
@@ -4,6 +4,8 @@
 
 #include "ui/app_list/views/tile_item_view.h"
 
+#include <utility>
+
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/views/app_list_main_view.h"
@@ -66,7 +68,7 @@
   title_->SetHandlesTooltips(false);
 
   AddChildView(icon_);
-  if (features::IsFullscreenAppListEnabled()) {
+  if (features::IsPlayStoreAppSearchEnabled()) {
     badge_ = new views::ImageView();
     badge_->set_can_process_events_within_subtree(false);
     badge_->SetVerticalAlignment(views::ImageView::LEADING);
diff --git a/ui/app_list/views/tile_item_view.h b/ui/app_list/views/tile_item_view.h
index 7f34448..c389bc2 100644
--- a/ui/app_list/views/tile_item_view.h
+++ b/ui/app_list/views/tile_item_view.h
@@ -5,6 +5,8 @@
 #ifndef UI_APP_LIST_VIEWS_TILE_ITEM_VIEW_H_
 #define UI_APP_LIST_VIEWS_TILE_ITEM_VIEW_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "third_party/skia/include/core/SkColor.h"
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 8c6d262..8d4bf832 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -660,8 +660,7 @@
 
 }  // namespace
 
-class GestureRecognizerTest : public AuraTestBase,
-                              public ::testing::WithParamInterface<bool> {
+class GestureRecognizerTest : public AuraTestBase {
  public:
   GestureRecognizerTest() {}
 
diff --git a/ui/aura/mus/mus_context_factory.cc b/ui/aura/mus/mus_context_factory.cc
index 539350d9..bfe06f3 100644
--- a/ui/aura/mus/mus_context_factory.cc
+++ b/ui/aura/mus/mus_context_factory.cc
@@ -19,8 +19,8 @@
 namespace aura {
 
 namespace {
-cc::BufferToTextureTargetMap CreateBufferToTextureTargetMap() {
-  cc::BufferToTextureTargetMap image_targets;
+viz::BufferToTextureTargetMap CreateBufferToTextureTargetMap() {
+  viz::BufferToTextureTargetMap image_targets;
   for (int usage_idx = 0; usage_idx <= static_cast<int>(gfx::BufferUsage::LAST);
        ++usage_idx) {
     gfx::BufferUsage usage = static_cast<gfx::BufferUsage>(usage_idx);
@@ -96,7 +96,7 @@
   return raster_thread_helper_.task_graph_runner();
 }
 
-const cc::ResourceSettings& MusContextFactory::GetResourceSettings() const {
+const viz::ResourceSettings& MusContextFactory::GetResourceSettings() const {
   return renderer_settings_.resource_settings;
 }
 
diff --git a/ui/aura/mus/mus_context_factory.h b/ui/aura/mus/mus_context_factory.h
index ea0c5d74..4c84377b 100644
--- a/ui/aura/mus/mus_context_factory.h
+++ b/ui/aura/mus/mus_context_factory.h
@@ -51,7 +51,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::ResourceSettings& GetResourceSettings() const override;
+  const viz::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override {}
   void RemoveObserver(ui::ContextFactoryObserver* observer) override {}
 
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 1d2ca0fd..1da128f8 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -89,6 +89,7 @@
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
     "//cc/surfaces:surfaces",
+    "//components/viz/common",
     "//components/viz/host",
     "//gpu/command_buffer/common",
     "//skia",
diff --git a/ui/compositor/DEPS b/ui/compositor/DEPS
index 1db43fd..7941025 100644
--- a/ui/compositor/DEPS
+++ b/ui/compositor/DEPS
@@ -2,6 +2,7 @@
   "+cc",
   "-cc/blink",
   "+components/viz/common/quads",
+  "+components/viz/common/resources",
   "+components/viz/host",
   "+gpu/command_buffer/client/gles2_interface.h",
   "+services/ui/public/cpp",
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 513fba2..353b9f9c 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -36,6 +36,7 @@
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "components/viz/common/quads/resource_format.h"
+#include "components/viz/common/resources/resource_settings.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/compositor_switches.h"
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 7a1b0a9..ada9570 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -47,7 +47,6 @@
 class LayerTreeFrameSink;
 class LayerTreeHost;
 class LocalSurfaceId;
-class ResourceSettings;
 class TaskGraphRunner;
 }
 
@@ -63,6 +62,7 @@
 
 namespace viz {
 class HostFrameSinkManager;
+class ResourceSettings;
 }
 
 namespace ui {
@@ -169,7 +169,7 @@
   virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0;
 
   // Gets the renderer settings.
-  virtual const cc::ResourceSettings& GetResourceSettings() const = 0;
+  virtual const viz::ResourceSettings& GetResourceSettings() const = 0;
 
   virtual void AddObserver(ContextFactoryObserver* observer) = 0;
 
diff --git a/ui/compositor/compositor_util.cc b/ui/compositor/compositor_util.cc
index e8464b8..04158b47 100644
--- a/ui/compositor/compositor_util.cc
+++ b/ui/compositor/compositor_util.cc
@@ -14,7 +14,7 @@
 namespace ui {
 
 cc::RendererSettings CreateRendererSettings(
-    const cc::BufferToTextureTargetMap& image_targets) {
+    const viz::BufferToTextureTargetMap& image_targets) {
   cc::RendererSettings renderer_settings;
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   renderer_settings.partial_swap_enabled =
diff --git a/ui/compositor/compositor_util.h b/ui/compositor/compositor_util.h
index 4ff21fd..85d9971 100644
--- a/ui/compositor/compositor_util.h
+++ b/ui/compositor/compositor_util.h
@@ -7,7 +7,7 @@
 
 #include <stdint.h>
 
-#include "cc/output/buffer_to_texture_target_map.h"
+#include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "ui/compositor/compositor_export.h"
 
 namespace cc {
@@ -17,7 +17,7 @@
 namespace ui {
 
 COMPOSITOR_EXPORT cc::RendererSettings CreateRendererSettings(
-    const cc::BufferToTextureTargetMap& image_targets);
+    const viz::BufferToTextureTargetMap& image_targets);
 
 }  // namespace ui
 
diff --git a/ui/compositor/test/fake_context_factory.cc b/ui/compositor/test/fake_context_factory.cc
index 1b396bd..73be3539 100644
--- a/ui/compositor/test/fake_context_factory.cc
+++ b/ui/compositor/test/fake_context_factory.cc
@@ -73,7 +73,7 @@
   return &task_graph_runner_;
 }
 
-const cc::ResourceSettings& FakeContextFactory::GetResourceSettings() const {
+const viz::ResourceSettings& FakeContextFactory::GetResourceSettings() const {
   return renderer_settings_.resource_settings;
 }
 
diff --git a/ui/compositor/test/fake_context_factory.h b/ui/compositor/test/fake_context_factory.h
index aadc8d6..5761aa2 100644
--- a/ui/compositor/test/fake_context_factory.h
+++ b/ui/compositor/test/fake_context_factory.h
@@ -36,7 +36,7 @@
   double GetRefreshRate() const override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
-  const cc::ResourceSettings& GetResourceSettings() const override;
+  const viz::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ui::ContextFactoryObserver* observer) override {}
   void RemoveObserver(ui::ContextFactoryObserver* observer) override {}
 
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 0693e7e..fde5a18 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -336,7 +336,7 @@
   per_compositor_data_[compositor]->display->Resize(size);
 }
 
-const cc::ResourceSettings& InProcessContextFactory::GetResourceSettings()
+const viz::ResourceSettings& InProcessContextFactory::GetResourceSettings()
     const {
   return renderer_settings_.resource_settings;
 }
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index 2bb2b20..9f52271 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -83,7 +83,7 @@
                                  base::TimeTicks timebase,
                                  base::TimeDelta interval) override {}
   void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {}
-  const cc::ResourceSettings& GetResourceSettings() const override;
+  const viz::ResourceSettings& GetResourceSettings() const override;
   void AddObserver(ContextFactoryObserver* observer) override;
   void RemoveObserver(ContextFactoryObserver* observer) override;
   cc::FrameSinkManager* GetFrameSinkManager() override;
diff --git a/ui/gfx/geometry/mojo/BUILD.gn b/ui/gfx/geometry/mojo/BUILD.gn
index 0e51ef9..f6cda9d 100644
--- a/ui/gfx/geometry/mojo/BUILD.gn
+++ b/ui/gfx/geometry/mojo/BUILD.gn
@@ -10,9 +10,6 @@
   sources = [
     "geometry.mojom",
   ]
-
-  # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  js_bindings_mode = "both"
 }
 
 mojom("test_interfaces") {
diff --git a/ui/gfx/icc_profile_mac.mm b/ui/gfx/icc_profile_mac.mm
index 70b899a..1aa768cc 100644
--- a/ui/gfx/icc_profile_mac.mm
+++ b/ui/gfx/icc_profile_mac.mm
@@ -4,20 +4,9 @@
 
 #include "ui/gfx/icc_profile.h"
 
-#include <AvailabilityMacros.h>
-
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
 
-#if defined(MAC_OS_X_VERSION_10_13) && \
-    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
-// https://crbug.com/729896, https://openradar.appspot.com/32883726
-#undef CGColorSpaceCopyICCProfile
-extern "C" {
-CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef);
-}  // extern "C"
-#endif  // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
-
 namespace gfx {
 
 // static
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index 3cf9b60..606c345 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -4,7 +4,6 @@
 
 #include "ui/gfx/mac/io_surface.h"
 
-#include <AvailabilityMacros.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -18,15 +17,6 @@
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/color_space_switches.h"
 
-#if defined(MAC_OS_X_VERSION_10_13) && \
-    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
-// https://crbug.com/729896, https://openradar.appspot.com/32883726
-#undef CGColorSpaceCopyICCProfile
-extern "C" {
-CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef);
-}  // extern "C"
-#endif  // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
-
 namespace gfx {
 
 namespace {
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index f89a699..3c99f3b 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -194,6 +194,10 @@
   // By default, just executing the SwapBuffers is normally enough.
 }
 
+void GLSurface::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  NOTIMPLEMENTED();
+}
+
 GLSurface* GLSurface::GetCurrent() {
   return current_surface_.Pointer()->Get();
 }
@@ -397,6 +401,10 @@
   surface_->WaitForSnapshotRendering();
 }
 
+void GLSurfaceAdapter::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  surface_->SetRelyOnImplicitSync(rely_on_implicit_sync);
+}
+
 GLSurfaceAdapter::~GLSurfaceAdapter() {}
 
 scoped_refptr<GLSurface> InitializeGLSurfaceWithFormat(
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 2b24c76d..c93a61e 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -225,6 +225,10 @@
   // calling this.
   virtual void WaitForSnapshotRendering();
 
+  // Tells the surface to rely on implicit or explicit sync when swapping
+  // buffers.
+  virtual void SetRelyOnImplicitSync(bool rely_on_implicit_sync);
+
   static GLSurface* GetCurrent();
 
  protected:
@@ -298,6 +302,7 @@
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   gfx::Vector2d GetDrawOffset() const override;
   void WaitForSnapshotRendering() override;
+  void SetRelyOnImplicitSync(bool rely_on_implicit_sync) override;
 
   GLSurface* surface() const { return surface_.get(); }
 
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 36a73ff366..5047e94 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -52,12 +52,6 @@
 platform_list_txt_file = "$target_gen_dir/platform_list.txt"
 constructor_list_cc_file = "$target_gen_dir/constructor_list.cc"
 
-config("vgem_map") {
-  if (use_vgem_map) {
-    defines = [ "USE_VGEM_MAP" ]
-  }
-}
-
 component("ozone_base") {
   sources = [
     "ozone_base_export.h",
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index a330ec1b..8e81051 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -8,13 +8,6 @@
 declare_args() {
   # Select platforms automatically. Turn this off for manual control.
   ozone_auto_platforms = use_ozone
-
-  # This enables memory-mapped access to accelerated graphics buffers via the
-  # VGEM ("virtual GEM") driver. This is currently only available on Chrome OS
-  # kernels and affects code in the GBM ozone platform.
-  # TODO(dshwang): remove this flag when all gbm hardware supports vgem map.
-  # crbug.com/519587
-  use_vgem_map = false
 }
 
 declare_args() {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 7c3cba7..8f2b739 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -115,6 +115,15 @@
   frame->callback = surface_swap_callback;
   unsubmitted_frames_.push_back(base::MakeUnique<PendingFrame>());
 
+  // TODO(dcastagna): Remove the following workaround once we get explicit sync
+  // on Intel.
+  // We can not rely on implicit sync on external devices (crbug.com/692508).
+  if (rely_on_implicit_sync_ && !IsOnExternalDrmDevice()) {
+    frame->ready = true;
+    SubmitFrame();
+    return;
+  }
+
   // TODO: the following should be replaced by a per surface flush as it gets
   // implemented in GL drivers.
   EGLSyncKHR fence = InsertFence(has_implicit_external_sync_);
@@ -167,6 +176,10 @@
   return config_;
 }
 
+void GbmSurfaceless::SetRelyOnImplicitSync(bool rely_on_implicit_sync) {
+  rely_on_implicit_sync_ = rely_on_implicit_sync;
+}
+
 GbmSurfaceless::~GbmSurfaceless() {
   Destroy();  // The EGL surface must be destroyed before SurfaceOzone.
   surface_factory_->UnregisterSurface(window_->widget());
@@ -235,4 +248,8 @@
   SubmitFrame();
 }
 
+bool GbmSurfaceless::IsOnExternalDrmDevice() {
+  return planes_.empty() ? false : planes_[0].buffer->RequiresGlFinish();
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 1ec916ca..a12fcfa0 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -54,6 +54,7 @@
                           int height,
                           const SwapCompletionCallback& callback) override;
   EGLConfig GetConfig() override;
+  void SetRelyOnImplicitSync(bool rely_on_implicit_sync) override;
 
  protected:
   ~GbmSurfaceless() override;
@@ -82,6 +83,8 @@
   void SwapCompleted(const SwapCompletionCallback& callback,
                      gfx::SwapResult result);
 
+  bool IsOnExternalDrmDevice();
+
   GbmSurfaceFactory* surface_factory_;
   std::unique_ptr<DrmWindowProxy> window_;
   std::vector<OverlayPlane> planes_;
@@ -93,6 +96,7 @@
   bool has_implicit_external_sync_;
   bool last_swap_buffers_result_ = true;
   bool swap_buffers_pending_ = false;
+  bool rely_on_implicit_sync_ = false;
 
   base::WeakPtrFactory<GbmSurfaceless> weak_factory_;
 
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp b/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp
index 373a0a4..57444755 100644
--- a/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/compiled_resources2.gyp
@@ -5,10 +5,18 @@
   'targets': [
     {
       'target_name': 'cr_camera',
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+        'cr_camera',
+        'cr_picture_types',
       ],
+      'target_name': 'cr_picture_preview',
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'cr_picture_types',
       'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
   ],
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.html b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.html
index d3c588b6..fead52c 100644
--- a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.html
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.html
@@ -64,23 +64,21 @@
         margin: 0 auto 0 auto;
       }
     </style>
-    <div hidden="[[!cameraActive]]">
-      <div id="perspectiveBox">
-        <div id="userImageStreamCrop">
-          <video id="cameraVideo" autoplay hidden="[[!cameraOnline_]]"></video>
-          <paper-spinner active="[[!cameraOnline_]]"></paper-spinner>
-        </div>
+    <div id="perspectiveBox">
+      <div id="userImageStreamCrop">
+        <video id="cameraVideo" autoplay hidden="[[!cameraOnline_]]"></video>
+        <paper-spinner active="[[!cameraOnline_]]"></paper-spinner>
       </div>
-      <div id="cameraControls">
-        <button is="paper-icon-button-light" id="flipPhoto" tabindex="2"
-            title="[[flipPhotoLabel]]" on-tap="onTapFlipPhoto_"
-            disabled="[[!cameraOnline_]]">
-        </button>
-        <button is="paper-icon-button-light" id="takePhoto" tabindex="1"
-            title="[[takePhotoLabel]]" on-tap="takePhoto"
-            disabled="[[!cameraOnline_]]">
-        </button>
-      </div>
+    </div>
+    <div id="cameraControls">
+      <button is="paper-icon-button-light" id="flipPhoto" tabindex="2"
+          title="[[flipPhotoLabel]]" on-tap="onTapFlipPhoto_"
+          disabled="[[!cameraOnline_]]">
+      </button>
+      <button is="paper-icon-button-light" id="takePhoto" tabindex="1"
+          title="[[takePhotoLabel]]" on-tap="takePhoto"
+          disabled="[[!cameraOnline_]]">
+      </button>
     </div>
   </template>
   <script src="cr_camera.js"></script>
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.js b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.js
index 77c6120..0d06a9e 100644
--- a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.js
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_camera.js
@@ -19,16 +19,6 @@
   is: 'cr-camera',
 
   properties: {
-    /**
-     * True if the user has selected the camera as the user image source.
-     * @type {boolean}
-     */
-    cameraActive: {
-      type: Boolean,
-      observer: 'cameraActiveChanged_',
-      value: false,
-    },
-
     /** Strings provided by host */
     flipPhotoLabel: String,
     takePhotoLabel: String,
@@ -58,13 +48,12 @@
     this.$.cameraVideo.addEventListener('canplay', function() {
       this.cameraOnline_ = true;
     }.bind(this));
-    if (this.cameraActive)
-      this.startCamera_();
+    this.startCamera();
   },
 
   /** @override */
   detached: function() {
-    this.stopCamera_();
+    this.stopCamera();
   },
 
   /**
@@ -88,20 +77,9 @@
     this.fire('photo-taken', {photoDataUrl: photoDataUrl});
   },
 
-  /** @private */
-  cameraActiveChanged_: function() {
-    if (this.cameraActive)
-      this.startCamera_();
-    else
-      this.stopCamera_();
-  },
-
-  /**
-   * Tries to start the camera stream capture.
-   * @private
-   */
-  startCamera_: function() {
-    this.stopCamera_();
+  /** Tries to start the camera stream capture. */
+  startCamera: function() {
+    this.stopCamera();
     this.cameraStartInProgress_ = true;
 
     var successCallback = function(stream) {
@@ -122,11 +100,8 @@
     navigator.webkitGetUserMedia({video: true}, successCallback, errorCallback);
   },
 
-  /**
-   * Stops camera capture, if it's currently active.
-   * @private
-   */
-  stopCamera_: function() {
+  /** Stops the camera stream capture if it's currently active. */
+  stopCamera: function() {
     this.cameraOnline_ = false;
     this.$.cameraVideo.src = '';
     if (this.cameraStream_)
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.html b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.html
new file mode 100644
index 0000000..e2ec0145
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.html
@@ -0,0 +1,49 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="cr_camera.html">
+<link rel="import" href="cr_picture_types.html">
+
+<dom-module id="cr-picture-preview">
+  <template>
+    <style include="cr-shared-style">
+      img {
+        display: block;
+        width: 100%;
+      }
+
+      #discard {
+        background-color: var(--paper-grey-800);
+        border-bottom-left-radius: 2px;
+        border-bottom-right-radius: 2px;
+        padding: 8px;
+      }
+
+      #discard button {
+        --iron-icon-fill-color: white;
+        background-color: var(--paper-red-500);
+        border-radius: 50%;
+        display: block;
+        margin: 0 auto 0 auto;
+      }
+    </style>
+    <template is="dom-if"
+        if="[[showImagePreview_(cameraActive_, imageSrc)]]">
+      <img alt="[[previewAltText]]" src="[[imageSrc]]">
+      <div id="discard" hidden="[[!showDiscard_(imageType)]]">
+        <button is="paper-icon-button-light" id="discardImage"
+            class="icon-delete" title="[[discardImageLabel]]"
+            on-tap="onTapDiscardImage_">
+        </button>
+      </div>
+    </template>
+    <template is="dom-if" if="[[cameraActive_]]">
+      <cr-camera id="camera"
+          flip-photo-label="[[flipPhotoLabel]]"
+          take-photo-label="[[takePhotoLabel]]">
+      </cr-camera>
+    </template>
+  </template>
+  <script src="cr_picture_preview.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.js b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.js
new file mode 100644
index 0000000..baae7b92
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.js
@@ -0,0 +1,94 @@
+// 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.
+
+/**
+ * @fileoverview
+ * 'cr-picture-preview' is a Polymer element used to show either a profile
+ * picture or a camera image preview.
+ */
+
+Polymer({
+  is: 'cr-picture-preview',
+
+  properties: {
+    /** Whether the camera is present / available */
+    cameraPresent: Boolean,
+
+    /** Image source to show when imageType != CAMERA. */
+    imageSrc: String,
+
+    /**
+     * The type of image to display in the preview.
+     * @type {CrPicture.SelectionTypes}
+     */
+    imageType: {
+      type: String,
+      value: CrPicture.SelectionTypes.NONE,
+    },
+
+    /** Strings provided by host */
+    discardImageLabel: String,
+    flipPhotoLabel: String,
+    previewAltText: String,
+    takePhotoLabel: String,
+
+    /** Whether the camera should be shown and active (started). */
+    cameraActive_: {
+      type: Boolean,
+      computed: 'getCameraActive_(cameraPresent, imageType)',
+      observer: 'cameraActiveChanged_',
+    },
+  },
+
+  /**
+   * Tells the camera to take a photo; the camera will fire a 'photo-taken'
+   * event when the photo is completed.
+   */
+  takePhoto: function() {
+    var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
+    if (camera)
+      camera.takePhoto();
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  getCameraActive_() {
+    return this.cameraPresent &&
+        this.imageType == CrPicture.SelectionTypes.CAMERA;
+  },
+
+  /** @private */
+  cameraActiveChanged_: function() {
+    var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
+    if (!camera)
+      return;  // Camera will be started when attached.
+    if (this.cameraActive_)
+      camera.startCamera();
+    else
+      camera.stopCamera();
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showImagePreview_: function() {
+    return !this.cameraActive_ && !!this.imageSrc;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showDiscard_: function() {
+    return this.imageType == CrPicture.SelectionTypes.OLD;
+  },
+
+  /** @private */
+  onTapDiscardImage_: function() {
+    this.fire('discard-image');
+  },
+});
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.html b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.html
new file mode 100644
index 0000000..f6194ba
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.html
@@ -0,0 +1 @@
+<script src="cr_picture_types.js"></script>
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.js b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.js
new file mode 100644
index 0000000..e980ef0
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.js
@@ -0,0 +1,30 @@
+// 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.
+
+var CrPicture = {};
+
+/**
+ * Contains the possible types for picture list image elements.
+ * @enum {string}
+ */
+CrPicture.SelectionTypes = {
+  CAMERA: 'camera',
+  FILE: 'file',
+  PROFILE: 'profile',
+  OLD: 'old',
+  DEFAULT: 'default',
+  NONE: '',
+};
+
+/**
+ * An picture list image element.
+ * @typedef {{
+ *   dataset: {
+ *     type: !CrPicture.SelectionTypes,
+ *     index: (number|undefined),
+ *   },
+ *   src: string,
+ * }}
+ */
+CrPicture.ImageElement;
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 3b5bf6d..da956d7 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -48,6 +48,18 @@
     <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__CAMERA_JS"
                file="../../webui/resources/cr_elements/chromeos/change_picture/cr_camera.js"
                type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR_PICTURE_PREVIEW_HTML"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.html"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__PICTURE_PREVIEW_JS"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_preview.js"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR_PICTURE_TYPES_HTML"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.html"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__PICTURE_TYPES_JS"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_types.js"
+               type="chrome_html" />
     <structure name="IDR_CR_ELEMENTS_CHROMEOS_CR_NETWORK_ICON_HTML"
                file="../../webui/resources/cr_elements/chromeos/network/cr_network_icon.html"
                type="chrome_html" />
diff --git a/ui/webui/resources/js/load_time_data.js b/ui/webui/resources/js/load_time_data.js
index 3282b68..3439a24a 100644
--- a/ui/webui/resources/js/load_time_data.js
+++ b/ui/webui/resources/js/load_time_data.js
@@ -8,6 +8,10 @@
  * content has finished loading). This data includes both localized strings and
  * any data that is important to have ready from a very early stage (e.g. things
  * that must be displayed right away).
+ *
+ * Note that loadTimeData is not guaranteed to be consistent between page
+ * refreshes (https://crbug.com/740629) and should not contain values that might
+ * change if the page is re-opened later.
  */
 
 /** @type {!LoadTimeData} */ var loadTimeData;