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..81c1b8c 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': 'e401f2c718fc5a0e279084bd51e72992f087fb7a',
   # 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': 'e19aed3c064f77ce4a8cbe02eb039160fae86cbd',
   # 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': 'fc9479ad5e3b6a9863ba6d8517535d9b7a8e95f8',
   # 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/WATCHLISTS b/WATCHLISTS
index 0863816..ff7ea623 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -173,7 +173,6 @@
                   'chrome/browser/android/banners/|'\
                   'chrome/browser/banners/|'\
                   'chrome/browser/ui/android/infobars/app_banner_.*|'\
-                  'chrome/renderer/banners/|'\
                   'third_party/WebKit/public/platform/modules/app_banner/|'\
                   'third_party/WebKit/Source/modules/app_banner/',
     },
@@ -578,6 +577,9 @@
                   'content/renderer/input|'\
                   'ui/events/blink/'
     },
+    'installable': {
+      'filepath': 'chrome/browser/installable/',
+    },
     'installer': {
       'filepath': 'chrome/install(_static|er)/',
     },
@@ -993,6 +995,9 @@
     'service_worker': {
       'filepath': 'content/(browser|renderer|child|common)/service_worker/',
     },
+    'services_public': {
+      'filepath': 'services/([^/]*/)*public/',
+    },
     'settings_reset_prompt': {
       'filepath': 'chrome/browser/safe_browsing/settings_reset_prompt/'\
                   '|chrome/browser/ui/views/settings_reset_prompt',
@@ -1661,7 +1666,8 @@
                     'dtrainor+watch@chromium.org'],
     'android_uma_settings': ['asvitkine+watch@chromium.org',
                              'gayane+watch@chromium.org'],
-    'android_webapk': ['zpeng+watch@chromium.org'],
+    'android_webapk': ['dominickn+watch@chromium.org',
+                       'zpeng+watch@chromium.org'],
     'android_webview': ['android-webview-reviews@chromium.org'],
     'app_list': ['mgiuca@chromium.org',
                  'tfarina@chromium.org'],
@@ -1895,8 +1901,7 @@
     'blink_w3ctests': ['blink-reviews-w3ctests@chromium.org'],
     'blink_web': ['kinuko+watch@chromium.org',
                   'platform-architecture-syd+reviews-web@chromium.org'],
-    'blink_webcomponents': ['dglazkov+blink@chromium.org',
-                            'webcomponents-bugzilla@chromium.org'],
+    'blink_webcomponents': ['dglazkov+blink@chromium.org'],
     'blink_webp': ['jzern@chromium.org',
                    'skal@google.com',
                    'urvang@chromium.org'],
@@ -2063,6 +2068,7 @@
                    'jsbell+idb@chromium.org'],
     'ink_drop': ['bruthig+ink_drop@chromium.org'],
     'input': ['dtapuska+chromiumwatch@chromium.org'],
+    'installable': ['dominickn+watch@chromium.org'],
     'installer': ['grt+watch@chromium.org',
                   'pennymac+watch@chromium.org',
                   'wfh+watch@chromium.org'],
@@ -2195,7 +2201,8 @@
                    'teravest+watch@chromium.org',
                    'tzik@chromium.org',
                    'yusukes+watch@chromium.org'],
-    'permissions': ['mlamouri+watch-permissions@chromium.org',
+    'permissions': ['dominickn+watch@chromium.org',
+                    'mlamouri+watch-permissions@chromium.org',
                     'raymes+watch@chromium.org'],
     'plugin': ['jam@chromium.org'],
     'polymer': ['michaelpg+watch-polymer@chromium.org'],
@@ -2227,6 +2234,7 @@
                        'serviceworker-reviews@chromium.org',
                        'shimazu+serviceworker@chromium.org',
                        'tzik@chromium.org'],
+    'services_public': ['blundell+services-watchlist@chromium.org'],
     'settings_reset_prompt': ['alito+watch@chromium.org'],
     'site_engagement': ['dominickn+watch@chromium.org'],
     'site_instance': ['ajwong+watch@chromium.org',
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..4856e17 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -7,8 +7,8 @@
 #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"
 #include "android_webview/browser/net/aw_network_change_notifier_factory.h"
 #include "android_webview/common/aw_descriptors.h"
@@ -134,13 +134,15 @@
     }
   }
 
-  if (AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabled()) {
-    base::FilePath safe_browsing_dir;
-    if (PathService::Get(android_webview::DIR_SAFE_BROWSING,
-                         &safe_browsing_dir)) {
-      if (!base::PathExists(safe_browsing_dir))
-        base::CreateDirectory(safe_browsing_dir);
-    }
+  // We need to create the safe browsing specific directory even if the
+  // AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabled() is false
+  // initially, because safe browsing can be enabled later at runtime
+  // on a per-webview basis.
+  base::FilePath safe_browsing_dir;
+  if (PathService::Get(android_webview::DIR_SAFE_BROWSING,
+                       &safe_browsing_dir)) {
+    if (!base::PathExists(safe_browsing_dir))
+      base::CreateDirectory(safe_browsing_dir);
   }
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -150,6 +152,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/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
index 286bc70b..858c29a 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
@@ -257,7 +257,7 @@
         }
     }
 
-    private static class WebResourceRequestImpl implements WebResourceRequest {
+    protected static class WebResourceRequestImpl implements WebResourceRequest {
         private final AwWebResourceRequest mRequest;
 
         public WebResourceRequestImpl(AwWebResourceRequest request) {
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..c270fa0 100644
--- a/ash/mus/shell_delegate_mus.cc
+++ b/ash/mus/shell_delegate_mus.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_util.h"
 #include "components/user_manager/user_info_impl.h"
 #include "ui/gfx/image/image.h"
+#include "ui/keyboard/keyboard_ui.h"
 
 #if defined(USE_OZONE)
 #include "services/ui/public/cpp/input_devices/input_device_controller_client.h"
@@ -40,7 +41,7 @@
 
 bool ShellDelegateMus::IsMultiProfilesEnabled() const {
   NOTIMPLEMENTED();
-  return false;
+  return true;  // For manual testing of multi-profile under mash.
 }
 
 bool ShellDelegateMus::IsRunningInForcedAppMode() const {
@@ -70,7 +71,7 @@
   NOTIMPLEMENTED();
 }
 
-keyboard::KeyboardUI* ShellDelegateMus::CreateKeyboardUI() {
+std::unique_ptr<keyboard::KeyboardUI> ShellDelegateMus::CreateKeyboardUI() {
   NOTIMPLEMENTED();
   return nullptr;
 }
diff --git a/ash/mus/shell_delegate_mus.h b/ash/mus/shell_delegate_mus.h
index aa9c165..00c6b38 100644
--- a/ash/mus/shell_delegate_mus.h
+++ b/ash/mus/shell_delegate_mus.h
@@ -31,7 +31,7 @@
   void PreInit() override;
   void PreShutdown() override;
   void Exit() override;
-  keyboard::KeyboardUI* CreateKeyboardUI() override;
+  std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   void ShelfInit() override;
   void ShelfShutdown() override;
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/root_window_controller.cc b/ash/root_window_controller.cc
index 756903c..2351d29 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -620,6 +620,8 @@
   aura::Window* keyboard_container = keyboard_controller->GetContainerWindow();
   keyboard_container->set_id(kShellWindowId_VirtualKeyboardContainer);
   parent->AddChild(keyboard_container);
+
+  keyboard_controller->LoadKeyboardUiInBackground();
 }
 
 void RootWindowController::DeactivateKeyboard(
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 14f72f2..706b57f 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -913,8 +913,6 @@
 
   aura::Window* keyboard_window =
       keyboard::KeyboardController::GetInstance()->ui()->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(gfx::Rect());
   keyboard_window->Show();
 
@@ -968,8 +966,6 @@
   keyboard::KeyboardController* controller =
       keyboard::KeyboardController::GetInstance();
   aura::Window* keyboard_window = controller->ui()->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), 100));
   keyboard_window->Show();
@@ -1005,8 +1001,6 @@
 
   aura::Window* keyboard_window =
       keyboard::KeyboardController::GetInstance()->ui()->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), 100));
 
@@ -1055,8 +1049,6 @@
 
   const int keyboard_height = 100;
   aura::Window* keyboard_window = ui->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), keyboard_height));
   keyboard_window->Show();
@@ -1103,8 +1095,6 @@
   ASSERT_TRUE(keyboard_container);
   keyboard_container->Show();
   aura::Window* keyboard_window = ui->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   keyboard_window->SetBounds(keyboard::FullWidthKeyboardBoundsFromRootBounds(
       primary_root_window->bounds(), keyboard_height));
   keyboard_window->Show();
@@ -1151,8 +1141,6 @@
 
   const int keyboard_height = 200;
   aura::Window* keyboard_window = ui->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   gfx::Rect keyboard_bounds = keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), keyboard_height);
   keyboard_window->SetBounds(keyboard_bounds);
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/shelf/shelf.cc b/ash/shelf/shelf.cc
index b57c791..3199ee8 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -142,7 +142,9 @@
 }
 
 void Shelf::SetAlignment(ShelfAlignment alignment) {
-  DCHECK(shelf_layout_manager_);
+  // Checks added for http://crbug.com/738011.
+  CHECK(shelf_widget_);
+  CHECK(shelf_layout_manager_);
 
   if (alignment_ == alignment)
     return;
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 5e73ba1..294d577 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -219,6 +219,8 @@
 }
 
 void ShelfWidget::OnShelfAlignmentChanged() {
+  // Check added for http://crbug.com/738011.
+  CHECK(status_area_widget_);
   shelf_view_->OnShelfAlignmentChanged();
   status_area_widget_->UpdateAfterShelfAlignmentChange();
   delegate_view_->SchedulePaint();
diff --git a/ash/shell.cc b/ash/shell.cc
index 0a6cf55..797bb01 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -164,6 +164,7 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_switches.h"
+#include "ui/keyboard/keyboard_ui.h"
 #include "ui/keyboard/keyboard_util.h"
 #include "ui/views/corewm/tooltip_aura.h"
 #include "ui/views/corewm/tooltip_controller.h"
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 19aa9fb..04815eb0 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -96,8 +96,8 @@
   base::MessageLoop::current()->QuitWhenIdle();
 }
 
-keyboard::KeyboardUI* ShellDelegateImpl::CreateKeyboardUI() {
-  return new TestKeyboardUI;
+std::unique_ptr<keyboard::KeyboardUI> ShellDelegateImpl::CreateKeyboardUI() {
+  return base::MakeUnique<TestKeyboardUI>();
 }
 
 void ShellDelegateImpl::OpenUrlFromArc(const GURL& url) {}
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 477b927..b039c1c 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -33,7 +33,7 @@
   void PreInit() override;
   void PreShutdown() override;
   void Exit() override;
-  keyboard::KeyboardUI* CreateKeyboardUI() override;
+  std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   void ShelfInit() override;
   void ShelfShutdown() override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 8c51f2f..ac2578174 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -87,8 +87,8 @@
   // Invoked when the user uses Ctrl-Shift-Q to close chrome.
   virtual void Exit() = 0;
 
-  // Create a shell-specific keyboard::KeyboardUI
-  virtual keyboard::KeyboardUI* CreateKeyboardUI() = 0;
+  // Create a shell-specific keyboard::KeyboardUI.
+  virtual std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() = 0;
 
   // Opens the |url| in a new browser tab.
   virtual void OpenUrlFromArc(const GURL& url) = 0;
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/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index ead209a1..c1f370e 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -87,8 +87,8 @@
   num_exit_requests_++;
 }
 
-keyboard::KeyboardUI* TestShellDelegate::CreateKeyboardUI() {
-  return new TestKeyboardUI;
+std::unique_ptr<keyboard::KeyboardUI> TestShellDelegate::CreateKeyboardUI() {
+  return base::MakeUnique<TestKeyboardUI>();
 }
 
 void TestShellDelegate::OpenUrlFromArc(const GURL& url) {}
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h
index f8f7b26f..816542d 100644
--- a/ash/test/test_shell_delegate.h
+++ b/ash/test/test_shell_delegate.h
@@ -45,7 +45,7 @@
   void PreInit() override;
   void PreShutdown() override;
   void Exit() override;
-  keyboard::KeyboardUI* CreateKeyboardUI() override;
+  std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void ShelfInit() override;
   void ShelfShutdown() override;
   void OpenUrlFromArc(const GURL& url) override;
diff --git a/ash/wm/always_on_top_controller_unittest.cc b/ash/wm/always_on_top_controller_unittest.cc
index 8d508ff3..058fc04 100644
--- a/ash/wm/always_on_top_controller_unittest.cc
+++ b/ash/wm/always_on_top_controller_unittest.cc
@@ -79,8 +79,6 @@
   keyboard_container->Show();
   aura::Window* keyboard_window =
       keyboard_controller->ui()->GetKeyboardWindow();
-  keyboard_container->AddChild(keyboard_window);
-  keyboard_window->set_owned_by_parent(false);
   const int kKeyboardHeight = 200;
   gfx::Rect keyboard_bounds = keyboard::FullWidthKeyboardBoundsFromRootBounds(
       root_window->bounds(), kKeyboardHeight);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 66297135..50e0565 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",
@@ -604,6 +603,7 @@
     "numerics/safe_conversions.h",
     "numerics/safe_conversions_impl.h",
     "numerics/safe_math.h",
+    "numerics/safe_math_clang_gcc_impl.h",
     "numerics/safe_math_shared_impl.h",
     "numerics/saturated_arithmetic.h",
     "numerics/saturated_arithmetic_arm.h",
@@ -2097,7 +2097,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/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h
index 61c471e..2f7d16c3 100644
--- a/base/ios/scoped_critical_action.h
+++ b/base/ios/scoped_critical_action.h
@@ -39,8 +39,12 @@
    public:
     Core();
 
-    // Informs the OS that the background task has completed.
-    void EndBackgroundTask();
+    // Informs the OS that the background task has started. This is a
+    // static method to ensure that the instance has a non-zero refcount.
+    static void StartBackgroundTask(scoped_refptr<Core> core);
+    // Informs the OS that the background task has completed. This is a
+    // static method to ensure that the instance has a non-zero refcount.
+    static void EndBackgroundTask(scoped_refptr<Core> core);
 
    private:
     friend base::RefCountedThreadSafe<Core>;
diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm
index 9dad70e..3828fbc 100644
--- a/base/ios/scoped_critical_action.mm
+++ b/base/ios/scoped_critical_action.mm
@@ -14,46 +14,59 @@
 namespace ios {
 
 ScopedCriticalAction::ScopedCriticalAction()
-    : core_(new ScopedCriticalAction::Core()) {
+    : core_(base::MakeRefCounted<ScopedCriticalAction::Core>()) {
+  ScopedCriticalAction::Core::StartBackgroundTask(core_);
 }
 
 ScopedCriticalAction::~ScopedCriticalAction() {
-  core_->EndBackgroundTask();
+  ScopedCriticalAction::Core::EndBackgroundTask(core_);
 }
 
-// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when
-// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose
-// execution will continue (temporarily) even after the app is backgrounded.
-ScopedCriticalAction::Core::Core() {
-  scoped_refptr<ScopedCriticalAction::Core> core = this;
-  background_task_id_ = [[UIApplication sharedApplication]
-      beginBackgroundTaskWithExpirationHandler:^{
-        DLOG(WARNING) << "Background task with id " << background_task_id_
-                      << " expired.";
-        // Note if |endBackgroundTask:| is not called for each task before time
-        // expires, the system kills the application.
-        core->EndBackgroundTask();
-      }];
-  if (background_task_id_ == UIBackgroundTaskInvalid) {
-    DLOG(WARNING) <<
-        "beginBackgroundTaskWithExpirationHandler: returned an invalid ID";
-  } else {
-    VLOG(3) << "Beginning background task with id " << background_task_id_;
-  }
-}
+ScopedCriticalAction::Core::Core()
+    : background_task_id_(UIBackgroundTaskInvalid) {}
 
 ScopedCriticalAction::Core::~Core() {
   DCHECK_EQ(background_task_id_, UIBackgroundTaskInvalid);
 }
 
-void ScopedCriticalAction::Core::EndBackgroundTask() {
+// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when
+// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose
+// execution will continue (temporarily) even after the app is backgrounded.
+// static
+void ScopedCriticalAction::Core::StartBackgroundTask(scoped_refptr<Core> core) {
+  UIApplication* application = [UIApplication sharedApplication];
+  if (!application) {
+    return;
+  }
+
+  core->background_task_id_ =
+      [application beginBackgroundTaskWithExpirationHandler:^{
+        DLOG(WARNING) << "Background task with id " << core->background_task_id_
+                      << " expired.";
+        // Note if |endBackgroundTask:| is not called for each task before time
+        // expires, the system kills the application.
+        EndBackgroundTask(core);
+      }];
+
+  if (core->background_task_id_ == UIBackgroundTaskInvalid) {
+    DLOG(WARNING)
+        << "beginBackgroundTaskWithExpirationHandler: returned an invalid ID";
+  } else {
+    VLOG(3) << "Beginning background task with id "
+            << core->background_task_id_;
+  }
+}
+
+// static
+void ScopedCriticalAction::Core::EndBackgroundTask(scoped_refptr<Core> core) {
   UIBackgroundTaskIdentifier task_id;
   {
-    AutoLock lock_scope(background_task_id_lock_);
-    if (background_task_id_ == UIBackgroundTaskInvalid)
+    AutoLock lock_scope(core->background_task_id_lock_);
+    if (core->background_task_id_ == UIBackgroundTaskInvalid) {
       return;
-    task_id = background_task_id_;
-    background_task_id_ = UIBackgroundTaskInvalid;
+    }
+    task_id = core->background_task_id_;
+    core->background_task_id_ = UIBackgroundTaskInvalid;
   }
 
   VLOG(3) << "Ending background task with id " << task_id;
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index 67d18808..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/base/numerics/checked_math_impl.h b/base/numerics/checked_math_impl.h
index bf3a3077..6a650a0 100644
--- a/base/numerics/checked_math_impl.h
+++ b/base/numerics/checked_math_impl.h
@@ -20,15 +20,6 @@
 namespace base {
 namespace internal {
 
-// Probe for builtin math overflow support on Clang and version check on GCC.
-#if defined(__has_builtin)
-#define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow))
-#elif defined(__GNUC__)
-#define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5)
-#else
-#define USE_OVERFLOW_BUILTINS (0)
-#endif
-
 template <typename T>
 bool CheckedAddImpl(T x, T y, T* result) {
   static_assert(std::is_integral<T>::value, "Type must be integral");
@@ -58,9 +49,10 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static bool Do(T x, U y, V* result) {
-#if USE_OVERFLOW_BUILTINS
-    return !__builtin_add_overflow(x, y, result);
-#else
+    // TODO(jschuh) Make this "constexpr if" once we're C++17.
+    if (CheckedAddFastOp<T, U>::is_supported)
+      return CheckedAddFastOp<T, U>::Do(x, y, result);
+
     using Promotion = typename BigEnoughPromotion<T, U>::type;
     Promotion presult;
     // Fail if either operand is out of range for the promoted type.
@@ -76,7 +68,6 @@
     }
     *result = static_cast<V>(presult);
     return is_valid && IsValueInRangeForNumericType<V>(presult);
-#endif
   }
 };
 
@@ -109,9 +100,10 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static bool Do(T x, U y, V* result) {
-#if USE_OVERFLOW_BUILTINS
-    return !__builtin_sub_overflow(x, y, result);
-#else
+    // TODO(jschuh) Make this "constexpr if" once we're C++17.
+    if (CheckedSubFastOp<T, U>::is_supported)
+      return CheckedSubFastOp<T, U>::Do(x, y, result);
+
     using Promotion = typename BigEnoughPromotion<T, U>::type;
     Promotion presult;
     // Fail if either operand is out of range for the promoted type.
@@ -127,7 +119,6 @@
     }
     *result = static_cast<V>(presult);
     return is_valid && IsValueInRangeForNumericType<V>(presult);
-#endif
   }
 };
 
@@ -162,25 +153,10 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V>
   static bool Do(T x, U y, V* result) {
-#if USE_OVERFLOW_BUILTINS
-#if defined(__clang__)
-    // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
-    // support full-width, mixed-sign multiply builtins.
-    // https://crbug.com/613003
-    static const bool kUseMaxInt =
-        // Narrower type than uintptr_t is always safe.
-        std::numeric_limits<__typeof__(x * y)>::digits <
-            std::numeric_limits<intptr_t>::digits ||
-        // Safe for intptr_t and uintptr_t if the sign matches.
-        (IntegerBitsPlusSign<__typeof__(x * y)>::value ==
-             IntegerBitsPlusSign<intptr_t>::value &&
-         std::is_signed<T>::value == std::is_signed<U>::value);
-#else
-    static const bool kUseMaxInt = true;
-#endif
-    if (kUseMaxInt)
-      return !__builtin_mul_overflow(x, y, result);
-#endif
+    // TODO(jschuh) Make this "constexpr if" once we're C++17.
+    if (CheckedMulFastOp<T, U>::is_supported)
+      return CheckedMulFastOp<T, U>::Do(x, y, result);
+
     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
     // Verify the destination type can hold the result (always true for 0).
     if (!(IsValueInRangeForNumericType<Promotion>(x) &&
@@ -201,9 +177,6 @@
   }
 };
 
-// Avoid poluting the namespace once we're done with the macro.
-#undef USE_OVERFLOW_BUILTINS
-
 // Division just requires a check for a zero denominator or an invalid negation
 // on signed min/-1.
 template <typename T>
diff --git a/base/numerics/clamped_math_impl.h b/base/numerics/clamped_math_impl.h
index 7f8035c..53be8818 100644
--- a/base/numerics/clamped_math_impl.h
+++ b/base/numerics/clamped_math_impl.h
@@ -54,6 +54,10 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V = result_type>
   static V Do(T x, U y) {
+    // TODO(jschuh) Make this "constexpr if" once we're C++17.
+    if (ClampedAddFastOp<T, U>::is_supported)
+      return ClampedAddFastOp<T, U>::template Do<V>(x, y);
+
     V result;
     return CheckedAddOp<T, U>::Do(x, y, &result)
                ? result
@@ -74,6 +78,10 @@
   using result_type = typename MaxExponentPromotion<T, U>::type;
   template <typename V = result_type>
   static V Do(T x, U y) {
+    // TODO(jschuh) Make this "constexpr if" once we're C++17.
+    if (ClampedSubFastOp<T, U>::is_supported)
+      return ClampedSubFastOp<T, U>::template Do<V>(x, y);
+
     V result;
     return CheckedSubOp<T, U>::Do(x, y, &result)
                ? result
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
index c85e7c3..bd52e81 100644
--- a/base/numerics/safe_conversions.h
+++ b/base/numerics/safe_conversions.h
@@ -35,6 +35,14 @@
   }
 };
 
+// Simple wrapper for statically checking if a type's range is contained.
+template <typename Dst, typename Src>
+struct IsTypeInRangeForNumericType {
+  static const bool value =
+      internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+      internal::NUMERIC_RANGE_CONTAINED;
+};
+
 // checked_cast<> is analogous to static_cast<> for numeric types,
 // except that it CHECKs that the specified numeric conversion will not
 // overflow or underflow. NaN source will always trigger a CHECK.
diff --git a/base/numerics/safe_math_clang_gcc_impl.h b/base/numerics/safe_math_clang_gcc_impl.h
new file mode 100644
index 0000000..cc548cac
--- /dev/null
+++ b/base/numerics/safe_math_clang_gcc_impl.h
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace base {
+namespace internal {
+
+template <typename T, typename U>
+struct CheckedAddFastOp {
+  static const bool is_supported = true;
+  template <typename V>
+  __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+    return !__builtin_add_overflow(x, y, result);
+  }
+};
+
+template <typename T, typename U>
+struct CheckedSubFastOp {
+  static const bool is_supported = true;
+  template <typename V>
+  __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+    return !__builtin_sub_overflow(x, y, result);
+  }
+};
+
+template <typename T, typename U>
+struct CheckedMulFastOp {
+#if defined(__clang__)
+  // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
+  // support full-width, mixed-sign multiply builtins.
+  // https://crbug.com/613003
+  // We can support intptr_t, uintptr_t, or a smaller common type.
+  static const bool is_supported =
+      (IsTypeInRangeForNumericType<intptr_t, T>::value &&
+       IsTypeInRangeForNumericType<intptr_t, U>::value) ||
+      (IsTypeInRangeForNumericType<uintptr_t, T>::value &&
+       IsTypeInRangeForNumericType<uintptr_t, U>::value);
+#else
+  static const bool is_supported = true;
+#endif
+  template <typename V>
+  __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+    return !__builtin_mul_overflow(x, y, result);
+  }
+};
+
+// This is a placeholder until the ARM implementation lands in the next CL.
+template <typename T, typename U>
+struct ClampedAddFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static V Do(T, U) {
+    assert(false);
+    return 0;
+  }
+};
+
+// This is a placeholder until the ARM implementation lands in the next CL.
+template <typename T, typename U>
+struct ClampedSubFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static V Do(T, U) {
+    assert(false);
+    return 0;
+  }
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
diff --git a/base/numerics/safe_math_shared_impl.h b/base/numerics/safe_math_shared_impl.h
index c243e2636..6f87e245 100644
--- a/base/numerics/safe_math_shared_impl.h
+++ b/base/numerics/safe_math_shared_impl.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <cassert>
 #include <climits>
 #include <cmath>
 #include <cstdlib>
@@ -16,6 +17,74 @@
 
 #include "base/numerics/safe_conversions.h"
 
+// Where available use builtin math overflow support on Clang and GCC.
+#if !defined(__native_client__) &&                         \
+    ((defined(__clang__) &&                                \
+      ((__clang_major__ > 3) ||                            \
+       (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
+     (defined(__GNUC__) && __GNUC__ >= 5))
+#include "base/numerics/safe_math_clang_gcc_impl.h"
+
+// These are the placeholder implementations for platforms that don't provide
+// optimized builtin/intrinsic operations.
+#else
+namespace base {
+namespace internal {
+
+template <typename T, typename U>
+struct CheckedAddFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static bool Do(T, U, V*) {
+    assert(false);  // Should not be reached.
+    return false;
+  }
+};
+
+template <typename T, typename U>
+struct CheckedSubFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static bool Do(T, U, V*) {
+    assert(false);  // Should not be reached.
+    return false;
+  }
+};
+
+template <typename T, typename U>
+struct CheckedMulFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static bool Do(T, U, V*) {
+    assert(false);  // Should not be reached.
+    return false;
+  }
+};
+
+template <typename T, typename U>
+struct ClampedAddFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static V Do(T, U) {
+    assert(false);  // Should not be reached.
+    return false;
+  }
+};
+
+template <typename T, typename U>
+struct ClampedSubFastOp {
+  static const bool is_supported = false;
+  template <typename V>
+  static V Do(T, U) {
+    assert(false);  // Should not be reached.
+    return false;
+  }
+};
+
+}  // namespace internal
+}  // namespace base
+#endif
+
 namespace base {
 namespace internal {
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index cd64bda..8959e1e0 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -900,6 +900,10 @@
   results_tracker_.AddGlobalTag("OS_FREEBSD");
 #endif
 
+#if defined(OS_FUCHSIA)
+  results_tracker_.AddGlobalTag("OS_FUCHSIA");
+#endif
+
 #if defined(OS_IOS)
   results_tracker_.AddGlobalTag("OS_IOS");
 #endif
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 3e11382..2f8d74d 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -7,21 +7,15 @@
 #include <stdint.h>
 
 #include <memory>
-#include <utility>
 #include <vector>
 
-#include "base/bind_helpers.h"
 #include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/sequenced_worker_pool_owner.h"
 #include "base/test/test_io_thread.h"
-#include "base/test/trace_event_analyzer.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -33,14 +27,11 @@
 #include "base/trace_event/memory_dump_scheduler.h"
 #include "base/trace_event/memory_infra_background_whitelist.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_buffer.h"
-#include "base/trace_event/trace_config_memory_test_util.h"
 #include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
-using testing::AnyNumber;
 using testing::AtMost;
 using testing::Between;
 using testing::Invoke;
@@ -58,10 +49,6 @@
   return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
 }
 
-MATCHER(IsBackgroundDump, "") {
-  return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND;
-}
-
 namespace {
 
 const char* kMDPName = "TestDumpProvider";
@@ -72,7 +59,6 @@
     kWhitelistedMDPName, kBackgroundButNotSummaryWhitelistedMDPName, nullptr};
 const char* const kTestMDPWhitelistForSummary[] = {kWhitelistedMDPName,
                                                    nullptr};
-
 void RegisterDumpProvider(
     MemoryDumpProvider* mdp,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
@@ -183,31 +169,6 @@
   unsigned num_of_post_tasks_;
 };
 
-std::unique_ptr<trace_analyzer::TraceAnalyzer> GetDeserializedTrace() {
-  // Flush the trace into JSON.
-  trace_event::TraceResultBuffer buffer;
-  TraceResultBuffer::SimpleOutput trace_output;
-  buffer.SetOutputCallback(trace_output.GetCallback());
-  RunLoop run_loop;
-  buffer.Start();
-  auto on_trace_data_collected =
-      [](Closure quit_closure, trace_event::TraceResultBuffer* buffer,
-         const scoped_refptr<RefCountedString>& json, bool has_more_events) {
-        buffer->AddFragment(json->data());
-        if (!has_more_events)
-          quit_closure.Run();
-      };
-
-  trace_event::TraceLog::GetInstance()->Flush(Bind(
-      on_trace_data_collected, run_loop.QuitClosure(), Unretained(&buffer)));
-  run_loop.Run();
-  buffer.Finish();
-
-  // Analyze the JSON.
-  return WrapUnique(
-      trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
-}
-
 }  // namespace
 
 class MemoryDumpManagerTest : public testing::Test {
@@ -230,11 +191,8 @@
   // Blocks the current thread (spinning a nested message loop) until the
   // memory dump is complete. Returns:
   // - return value: the |success| from the CreateProcessDump() callback.
-  // - (optional) |result|: the summarized metrics for TestSummaryComputation.
-  bool RequestProcessDumpAndWait(
-      MemoryDumpType dump_type,
-      MemoryDumpLevelOfDetail level_of_detail,
-      Optional<MemoryDumpCallbackResult>* result = nullptr) {
+  bool RequestProcessDumpAndWait(MemoryDumpType dump_type,
+                                 MemoryDumpLevelOfDetail level_of_detail) {
     RunLoop run_loop;
     bool success = false;
     static uint64_t test_guid = 1;
@@ -250,40 +208,33 @@
     // around the limitation of Bind() in supporting only capture-less lambdas.
     ProcessMemoryDumpCallback callback = Bind(
         [](bool* curried_success, Closure curried_quit_closure,
-           uint64_t curried_expected_guid,
-           Optional<MemoryDumpCallbackResult>* curried_result, bool success,
-           uint64_t dump_guid,
+           uint64_t curried_expected_guid, bool success, uint64_t dump_guid,
            const Optional<MemoryDumpCallbackResult>& callback_result) {
           *curried_success = success;
           EXPECT_EQ(curried_expected_guid, dump_guid);
-          if (curried_result)
-            *curried_result = callback_result;
           ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                   curried_quit_closure);
         },
-        Unretained(&success), run_loop.QuitClosure(), test_guid, result);
+        Unretained(&success), run_loop.QuitClosure(), test_guid);
 
     mdm_->CreateProcessDump(request_args, callback);
     run_loop.Run();
     return success;
   }
 
-  void EnableTracingWithLegacyCategories(const char* category) {
-    TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
-                                        TraceLog::RECORDING_MODE);
+  void EnableForTracing() {
+    TraceLog::GetInstance()->SetEnabled(
+        TraceConfig(MemoryDumpManager::kTraceCategory, ""),
+        TraceLog::RECORDING_MODE);
   }
 
-  void EnableTracingWithTraceConfig(const std::string& trace_config) {
-    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+  void EnableForTracingWithTraceConfig(const std::string trace_config_string) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config_string),
                                         TraceLog::RECORDING_MODE);
   }
 
   void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
 
-  bool IsPeriodicDumpingEnabled() const {
-    return MemoryDumpScheduler::GetInstance()->is_enabled_for_testing();
-  }
-
   int GetMaxConsecutiveFailuresCount() const {
     return MemoryDumpManager::kMaxConsecutiveFailuresCount;
   }
@@ -307,7 +258,7 @@
 
   // Now repeat enabling the memory category and check that the dumper is
   // invoked this time.
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
   for (int i = 0; i < 3; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -319,7 +270,7 @@
 
   // Finally check the unregister logic: the global dump handler will be invoked
   // but not the dump provider, as it has been unregistered.
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
   for (int i = 0; i < 3; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -335,7 +286,7 @@
   MockMemoryDumpProvider mdp;
 
   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::DETAILED));
@@ -345,7 +296,7 @@
   // Check that requesting dumps with low level of detail actually propagates to
   // OnMemoryDump() call on dump providers.
   RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::LIGHT));
@@ -362,7 +313,7 @@
   RegisterDumpProvider(&mdp1, nullptr);
   RegisterDumpProvider(&mdp2, nullptr);
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   const HeapProfilerSerializationState* heap_profiler_serialization_state =
       mdm_->heap_profiler_serialization_state_for_testing().get();
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
@@ -400,7 +351,7 @@
 
   // Enable only mdp1.
   RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -410,7 +361,7 @@
   // Invert: enable mdp2 and disable mdp1.
   mdm_->UnregisterDumpProvider(&mdp1);
   RegisterDumpProvider(&mdp2, nullptr);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -419,7 +370,7 @@
 
   // Enable both mdp1 and mdp2.
   RegisterDumpProvider(&mdp1, nullptr);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_CALL(mdp1, OnMemoryDump(_, _));
   EXPECT_CALL(mdp2, OnMemoryDump(_, _));
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -443,7 +394,7 @@
 
   {
     EXPECT_CALL(mdp, OnMemoryDump(_, _));
-    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                           MemoryDumpLevelOfDetail::DETAILED));
     DisableTracing();
@@ -453,7 +404,7 @@
 
   {
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                           MemoryDumpLevelOfDetail::DETAILED));
     DisableTracing();
@@ -464,7 +415,7 @@
 
   {
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                           MemoryDumpLevelOfDetail::DETAILED));
     DisableTracing();
@@ -476,7 +427,7 @@
 
   {
     EXPECT_CALL(mdp, OnMemoryDump(_, _));
-    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    EnableForTracing();
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                           MemoryDumpLevelOfDetail::DETAILED));
     DisableTracing();
@@ -513,7 +464,7 @@
               return true;
             }));
   }
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   while (!threads.empty()) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -560,7 +511,7 @@
   EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2);
   EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2);
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   task_runner1->set_enabled(false);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
@@ -587,7 +538,7 @@
 
   RegisterDumpProvider(&mdp1, nullptr);
   RegisterDumpProvider(&mdp2, nullptr);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(GetMaxConsecutiveFailuresCount())
@@ -618,7 +569,7 @@
   MockMemoryDumpProvider mdp2;
 
   RegisterDumpProvider(&mdp1, nullptr);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(4)
@@ -650,7 +601,7 @@
 
   RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
   RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   EXPECT_CALL(mdp1, OnMemoryDump(_, _))
       .Times(4)
@@ -716,7 +667,7 @@
         .WillOnce(Invoke(on_dump));
   }
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::DETAILED));
   ASSERT_EQ(1, on_memory_dump_call_count);
@@ -724,56 +675,6 @@
   DisableTracing();
 }
 
-TEST_F(MemoryDumpManagerTest, TestPollingOnDumpThread) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider());
-  std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider());
-  mdp1->enable_mock_destructor = true;
-  mdp2->enable_mock_destructor = true;
-  EXPECT_CALL(*mdp1, Destructor());
-  EXPECT_CALL(*mdp2, Destructor());
-
-  MemoryDumpProvider::Options options;
-  options.is_fast_polling_supported = true;
-  RegisterDumpProvider(mdp1.get(), nullptr, options);
-
-  RunLoop run_loop;
-  auto test_task_runner = ThreadTaskRunnerHandle::Get();
-  auto quit_closure = run_loop.QuitClosure();
-  MemoryDumpManager* mdm = mdm_.get();
-
-  EXPECT_CALL(*mdp1, PollFastMemoryTotal(_))
-      .WillOnce(Invoke([&mdp2, options, this](uint64_t*) {
-        RegisterDumpProvider(mdp2.get(), nullptr, options);
-      }))
-      .WillOnce(Return())
-      .WillOnce(Invoke([mdm, &mdp2](uint64_t*) {
-        mdm->UnregisterAndDeleteDumpProviderSoon(std::move(mdp2));
-      }))
-      .WillOnce(Invoke([test_task_runner, quit_closure](uint64_t*) {
-        test_task_runner->PostTask(FROM_HERE, quit_closure);
-      }))
-      .WillRepeatedly(Return());
-
-  // We expect a call to |mdp1| because it is still registered at the time the
-  // Peak detector is Stop()-ed (upon OnTraceLogDisabled(). We do NOT expect
-  // instead a call for |mdp2|, because that gets unregisterd before the Stop().
-  EXPECT_CALL(*mdp1, SuspendFastMemoryPolling()).Times(1);
-  EXPECT_CALL(*mdp2, SuspendFastMemoryPolling()).Times(0);
-
-  // |mdp2| should invoke exactly twice:
-  // - once after the registrarion, when |mdp1| hits the first Return()
-  // - the 2nd time when |mdp1| unregisters |mdp1|. The unregistration is
-  //   posted and will necessarily happen after the polling task.
-  EXPECT_CALL(*mdp2, PollFastMemoryTotal(_)).Times(2).WillRepeatedly(Return());
-
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_PeakDetectionTrigger(1));
-  run_loop.Run();
-  DisableTracing();
-  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp1));
-}
-
 // If a thread (with a dump provider living on it) is torn down during a dump
 // its dump provider should be skipped but the dump itself should succeed.
 TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
@@ -815,7 +716,7 @@
         .WillOnce(Invoke(on_dump));
   }
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::DETAILED));
   ASSERT_EQ(1, on_memory_dump_call_count);
@@ -823,9 +724,9 @@
   DisableTracing();
 }
 
-// Checks that a NACK callback is invoked if CreateProcessDump() is called when
+// Checks that the callback is invoked if CreateProcessDump() is called when
 // tracing is not enabled.
-TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
+TEST_F(MemoryDumpManagerTest, TriggerDumpWithoutTracing) {
   InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
   MockMemoryDumpProvider mdp;
   RegisterDumpProvider(&mdp, nullptr);
@@ -834,167 +735,6 @@
                                          MemoryDumpLevelOfDetail::DETAILED));
 }
 
-// Checks that is the MemoryDumpManager is initialized after tracing already
-// began, it will still late-join the party (real use case: startup tracing).
-TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
-  MockMemoryDumpProvider mdp;
-  RegisterDumpProvider(&mdp, nullptr);
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
-  // First check that a CreateProcessDump() issued before the MemoryDumpManager
-  // initialization gets NACK-ed cleanly.
-  {
-    testing::InSequence sequence;
-    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                           MemoryDumpLevelOfDetail::DETAILED));
-  }
-
-  // Now late-initialize the MemoryDumpManager and check that the
-  // CreateProcessDump() completes successfully.
-  {
-    testing::InSequence sequence;
-    InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
-    EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                          MemoryDumpLevelOfDetail::DETAILED));
-  }
-  DisableTracing();
-}
-
-// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
-// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
-// dumps in memory-infra, handling gracefully the transition between the legacy
-// and the new-style (JSON-based) TraceConfig.
-TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-
-  // We don't need to create any dump in this test, only check whether the dumps
-  // are requested or not.
-
-  // Enabling memory-infra in a non-coordinator process should not trigger any
-  // periodic dumps.
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-  EXPECT_FALSE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-
-  // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
-  // process with a fully defined trigger config should NOT enable any periodic
-  // dumps.
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
-  EXPECT_FALSE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-}
-
-TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
-  InitializeMemoryDumpManagerForInProcessTesting(true /* is_coordinator */);
-
-  // Enabling memory-infra with the legacy TraceConfig (category filter) in
-  // a coordinator process should not enable periodic dumps.
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-  EXPECT_FALSE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-
-  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
-  // process while specifying a "memory_dump_config" section should enable
-  // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
-  // is: ticking memory-infra should dump periodically with an explicit config.
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(100, 5));
-  EXPECT_TRUE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-
-  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
-  // process with an empty "memory_dump_config" should NOT enable periodic
-  // dumps. This is the way telemetry is supposed to use memory-infra with
-  // only explicitly triggered dumps.
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
-  EXPECT_FALSE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-
-  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
-  // process with a fully defined trigger config should cause periodic dumps to
-  // be performed in the correct order.
-  RunLoop run_loop;
-  auto test_task_runner = ThreadTaskRunnerHandle::Get();
-  auto quit_closure = run_loop.QuitClosure();
-
-  const int kHeavyDumpRate = 5;
-  const int kLightDumpPeriodMs = 1;
-  const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
-
-  // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
-  auto mdp = MakeUnique<MockMemoryDumpProvider>();
-  RegisterDumpProvider(&*mdp, nullptr, kDefaultOptions, kWhitelistedMDPName);
-
-  testing::InSequence sequence;
-  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
-  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 1);
-  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
-  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 2);
-  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _))
-      .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
-                                                        ProcessMemoryDump*) {
-        test_task_runner->PostTask(FROM_HERE, quit_closure);
-        return true;
-      }));
-
-  // Swallow all the final spurious calls until tracing gets disabled.
-  EXPECT_CALL(*mdp, OnMemoryDump(_, _)).Times(AnyNumber());
-
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
-          kLightDumpPeriodMs, kHeavyDumpPeriodMs));
-  run_loop.Run();
-  DisableTracing();
-  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
-}
-
-TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
-  using trace_analyzer::Query;
-
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-
-  // Standard provider with default options (create dump for current process).
-  MemoryDumpProvider::Options options;
-  MockMemoryDumpProvider mdp1;
-  RegisterDumpProvider(&mdp1, nullptr, options);
-
-  // Provider with out-of-process dumping.
-  MockMemoryDumpProvider mdp2;
-  options.target_pid = 123;
-  RegisterDumpProvider(&mdp2, nullptr, options);
-
-  // Another provider with out-of-process dumping.
-  MockMemoryDumpProvider mdp3;
-  options.target_pid = 456;
-  RegisterDumpProvider(&mdp3, nullptr, options);
-
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1);
-  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1);
-  EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1);
-  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::DETAILED));
-  DisableTracing();
-
-  std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
-      GetDeserializedTrace();
-  trace_analyzer::TraceEventVector events;
-  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
-                       &events);
-
-  ASSERT_EQ(3u, events.size());
-  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
-  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
-  ASSERT_EQ(1u, trace_analyzer::CountMatches(
-                    events, Query::EventPidIs(GetCurrentProcId())));
-  ASSERT_EQ(events[0]->id, events[1]->id);
-  ASSERT_EQ(events[0]->id, events[2]->id);
-}
-
 TEST_F(MemoryDumpManagerTest, SummaryOnlyWhitelisting) {
   InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
 
@@ -1010,7 +750,7 @@
   RegisterDumpProvider(&backgroundMdp, nullptr, kDefaultOptions,
                        kBackgroundButNotSummaryWhitelistedMDPName);
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
 
   EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(0);
   EXPECT_CALL(summaryMdp, OnMemoryDump(_, _)).Times(1);
@@ -1019,38 +759,6 @@
   DisableTracing();
 }
 
-TEST_F(MemoryDumpManagerTest, SummaryOnlyDumpsArentAddedToTrace) {
-  using trace_analyzer::Query;
-
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  SetDumpProviderSummaryWhitelistForTesting(kTestMDPWhitelistForSummary);
-  SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
-
-  // Standard provider with default options (create dump for current process).
-  MockMemoryDumpProvider mdp;
-  RegisterDumpProvider(&mdp, nullptr, kDefaultOptions, kWhitelistedMDPName);
-
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
-  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(2);
-  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
-  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
-  DisableTracing();
-
-  std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
-      GetDeserializedTrace();
-  trace_analyzer::TraceEventVector events;
-  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
-                       &events);
-
-  ASSERT_EQ(1u, events.size());
-  ASSERT_TRUE(trace_analyzer::CountMatches(
-      events, Query::EventNameIs(MemoryDumpTypeToString(
-                  MemoryDumpType::EXPLICITLY_TRIGGERED))));
-}
-
 // Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
 // unregistration should actually delete the providers and not leak them.
 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
@@ -1109,7 +817,7 @@
         EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
       }));
 
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EnableForTracing();
   for (int i = 0; i < 2; ++i) {
     EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                           MemoryDumpLevelOfDetail::DETAILED));
@@ -1117,183 +825,5 @@
   DisableTracing();
 }
 
-TEST_F(MemoryDumpManagerTest, TestWhitelistingMDP) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
-  std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
-  RegisterDumpProvider(mdp1.get(), nullptr);
-  std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
-  RegisterDumpProvider(mdp2.get(), nullptr, kDefaultOptions,
-                       kWhitelistedMDPName);
-
-  EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0);
-  EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1);
-
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-  EXPECT_FALSE(IsPeriodicDumpingEnabled());
-  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::BACKGROUND));
-  DisableTracing();
-}
-
-// Configures periodic dumps with MemoryDumpLevelOfDetail::BACKGROUND triggers
-// and tests that only BACKGROUND are added to the trace, but not LIGHT or
-// DETAILED, even if requested explicitly.
-TEST_F(MemoryDumpManagerTest, TestBackgroundTracingSetup) {
-  InitializeMemoryDumpManagerForInProcessTesting(true /* is_coordinator */);
-
-  SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
-  auto mdp = MakeUnique<MockMemoryDumpProvider>();
-  RegisterDumpProvider(&*mdp, nullptr, kDefaultOptions, kWhitelistedMDPName);
-
-  RunLoop run_loop;
-  auto test_task_runner = ThreadTaskRunnerHandle::Get();
-  auto quit_closure = run_loop.QuitClosure();
-
-  {
-    testing::InSequence sequence;
-    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _)).Times(3);
-    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _))
-        .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
-                                                          ProcessMemoryDump*) {
-          test_task_runner->PostTask(FROM_HERE, quit_closure);
-          return true;
-        }));
-    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _)).Times(AnyNumber());
-  }
-
-  EnableTracingWithTraceConfig(
-      TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
-          1 /* period_ms */));
-
-  run_loop.Run();
-
-  // When requesting non-BACKGROUND dumps the MDP will be invoked but the
-  // data is expected to be dropped on the floor, hence the EXPECT_FALSE.
-  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _));
-  EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                         MemoryDumpLevelOfDetail::LIGHT));
-
-  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
-  EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                         MemoryDumpLevelOfDetail::DETAILED));
-
-  ASSERT_TRUE(IsPeriodicDumpingEnabled());
-  DisableTracing();
-  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
-}
-
-// Tests that the MemoryDumpProvider(s) are invoked even if tracing has not
-// been initialized.
-TEST_F(MemoryDumpManagerTest, DumpWithoutInitializingTracing) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  MockMemoryDumpProvider mdp;
-  RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-  DisableTracing();
-  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
-  for (int i = 0; i < 3; ++i) {
-    // The callback result will be false for the moment. true result means that
-    // as well as the dump being successful we also managed to add the dump to
-    // the trace. But the latter won't happen here.
-    EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                           MemoryDumpLevelOfDetail::DETAILED));
-  }
-  mdm_->UnregisterDumpProvider(&mdp);
-}
-
-// Similar to DumpWithoutInitializingTracing. Tracing is initialized but not
-// enabled.
-TEST_F(MemoryDumpManagerTest, DumpWithTracingInitializedButDisabled) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  MockMemoryDumpProvider mdp;
-  RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-
-  DisableTracing();
-
-  const TraceConfig& trace_config =
-      TraceConfig(TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
-  const TraceConfig::MemoryDumpConfig& memory_dump_config =
-      trace_config.memory_dump_config();
-  mdm_->SetupForTracing(memory_dump_config);
-
-  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
-  for (int i = 0; i < 3; ++i) {
-    // Same as the above. Even if the MDP(s) are invoked, this will return false
-    // while attempting to add the dump into the trace.
-    EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                           MemoryDumpLevelOfDetail::DETAILED));
-  }
-  mdm_->TeardownForTracing();
-  mdm_->UnregisterDumpProvider(&mdp);
-}
-
-TEST_F(MemoryDumpManagerTest, TestSummaryComputation) {
-  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
-  MockMemoryDumpProvider mdp;
-  RegisterDumpProvider(&mdp, ThreadTaskRunnerHandle::Get());
-
-  EXPECT_CALL(mdp, OnMemoryDump(_, _))
-      .WillOnce(Invoke([](const MemoryDumpArgs&,
-                          ProcessMemoryDump* pmd) -> bool {
-        auto* size = MemoryAllocatorDump::kNameSize;
-        auto* bytes = MemoryAllocatorDump::kUnitsBytes;
-        const uint32_t kB = 1024;
-
-        pmd->CreateAllocatorDump("malloc")->AddScalar(size, bytes, 1 * kB);
-        pmd->CreateAllocatorDump("malloc/ignored")
-            ->AddScalar(size, bytes, 99 * kB);
-
-        pmd->CreateAllocatorDump("blink_gc")->AddScalar(size, bytes, 2 * kB);
-        pmd->CreateAllocatorDump("blink_gc/ignored")
-            ->AddScalar(size, bytes, 99 * kB);
-
-        pmd->CreateAllocatorDump("v8/foo")->AddScalar(size, bytes, 1 * kB);
-        pmd->CreateAllocatorDump("v8/bar")->AddScalar(size, bytes, 2 * kB);
-        pmd->CreateAllocatorDump("v8")->AddScalar(size, bytes, 99 * kB);
-
-        // All the 99 KB values here are expected to be ignored.
-        pmd->CreateAllocatorDump("partition_alloc")
-            ->AddScalar(size, bytes, 99 * kB);
-        pmd->CreateAllocatorDump("partition_alloc/allocated_objects")
-            ->AddScalar(size, bytes, 99 * kB);
-        pmd->CreateAllocatorDump("partition_alloc/allocated_objects/ignored")
-            ->AddScalar(size, bytes, 99 * kB);
-        pmd->CreateAllocatorDump("partition_alloc/partitions")
-            ->AddScalar(size, bytes, 99 * kB);
-        pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_1")
-            ->AddScalar(size, bytes, 2 * kB);
-        pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_2")
-            ->AddScalar(size, bytes, 2 * kB);
-        pmd->process_totals()->set_resident_set_bytes(5 * kB);
-        pmd->set_has_process_totals();
-        return true;
-      }));
-
-  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-  Optional<MemoryDumpCallbackResult> result;
-  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
-                                        MemoryDumpLevelOfDetail::LIGHT,
-                                        &result));
-  DisableTracing();
-
-  ASSERT_TRUE(result);
-
-  // For malloc we only count the root "malloc" not children "malloc/*".
-  EXPECT_EQ(1u, result->chrome_dump.malloc_total_kb);
-
-  // For blink_gc we only count the root "blink_gc" not children "blink_gc/*".
-  EXPECT_EQ(2u, result->chrome_dump.blink_gc_total_kb);
-
-  // For v8 we count the children ("v8/*") as the root total is not given.
-  EXPECT_EQ(3u, result->chrome_dump.v8_total_kb);
-
-  // partition_alloc has partition_alloc/allocated_objects/* which is a subset
-  // of partition_alloc/partitions/* so we only count the latter.
-  EXPECT_EQ(4u, result->chrome_dump.partition_alloc_total_kb);
-
-  // resident_set_kb should read from process_totals.
-  EXPECT_EQ(5u, result->os_dump.resident_set_kb);
-};
-
 }  // namespace trace_event
 }  // namespace base
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/build/config/ios/Module-Info.plist b/build/config/ios/Module-Info.plist
index 63953d6..13b67c4 100644
--- a/build/config/ios/Module-Info.plist
+++ b/build/config/ios/Module-Info.plist
@@ -5,9 +5,9 @@
   <key>CFBundleDevelopmentRegion</key>
   <string>en</string>
   <key>CFBundleExecutable</key>
-  <string>${MODULE_NAME}</string>
+  <string>${EXECUTABLE_NAME}</string>
   <key>CFBundleIdentifier</key>
-  <string>${IOS_BUNDLE_ID_PREFIX}.test.${EXECUTABLE_NAME:rfc1034identifier}.${MODULE_NAME:rfc1034identifier}</string>
+  <string>${IOS_BUNDLE_ID_PREFIX}.${MODULE_BUNDLE_ID:rfc1034identifier}</string>
   <key>CFBundleInfoDictionaryVersion</key>
   <string>6.0</string>
   <key>CFBundleName</key>
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py
index b197bac7..de66654f 100644
--- a/build/config/ios/codesign.py
+++ b/build/config/ios/codesign.py
@@ -58,6 +58,27 @@
   def binary_path(self):
     return os.path.join(self._path, self._data['CFBundleExecutable'])
 
+  def Validate(self, expected_mappings):
+    """Checks that keys in the bundle have the expected value.
+
+    Args:
+      expected_mappings: a dictionary of string to object, each mapping will
+      be looked up in the bundle data to check it has the same value (missing
+      values will be ignored)
+
+    Returns:
+      A dictionary of the key with a different value between expected_mappings
+      and the content of the bundle (i.e. errors) so that caller can format the
+      error message. The dictionary will be empty if there are no errors.
+    """
+    errors = {}
+    for key, expected_value in expected_mappings.iteritems():
+      if key in self._data:
+        value = self._data[key]
+        if value != expected_value:
+          errors[key] = (value, expected_value)
+    return errors
+
 
 class ProvisioningProfile(object):
   """Wraps a mobile provisioning profile file."""
@@ -298,6 +319,34 @@
 
     bundle = Bundle(args.path)
 
+    # According to Apple documentation, the application binary must be the same
+    # as the bundle name without the .app suffix. See crbug.com/740476 for more
+    # information on what problem this can cause.
+    #
+    # To prevent this class of error, fail with an error if the binary name is
+    # incorrect in the Info.plist as it is not possible to update the value in
+    # Info.plist at this point (the file has been copied by a different target
+    # and ninja would consider the build dirty if it was updated).
+    #
+    # Also checks that the name of the bundle is correct too (does not cause the
+    # build to be considered dirty, but still terminate the script in case of an
+    # incorrect bundle name).
+    #
+    # Apple documentation is available at:
+    # https://developer.apple.com/library/content/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html
+    bundle_name = os.path.splitext(os.path.basename(bundle.path))[0]
+    errors = bundle.Validate({
+        'CFBundleName': bundle_name,
+        'CFBundleExecutable': bundle_name,
+    })
+    if errors:
+      for key in sorted(errors):
+        value, expected_value = errors[key]
+        sys.stderr.write('%s: error: %s value incorrect: %s != %s\n' % (
+            bundle.path, key, value, expected_value))
+      sys.stderr.flush()
+      sys.exit(1)
+
     # Delete existing embedded mobile provisioning.
     embedded_provisioning_profile = os.path.join(
         bundle.path, 'embedded.mobileprovision')
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 2716bf62..ece3b1d2 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -1453,14 +1453,11 @@
       executable_name = _target_name
 
       if (ios_automatically_manage_certs) {
-        # Use the same bundle identifier for EarlGrey tests as for unit tests
-        # when managing certificates as the number of free certs is limited.
-        extra_substitutions = [
-          "EXECUTABLE_NAME=gtest.${ios_generic_test_bundle_id_suffix}",
-          "MODULE_NAME=${ios_generic_test_bundle_id_suffix}-module",
-        ]
+        # Use a fixed bundle identifier for EarlGrey tests when using Xcode to
+        # manage the certificates as the number of free certs is limited.
+        extra_substitutions = [ "MODULE_BUNDLE_ID=gtest.${ios_generic_test_bundle_id_suffix}-module" ]
       } else {
-        extra_substitutions = [ "MODULE_NAME=$_output_name" ]
+        extra_substitutions = [ "MODULE_BUNDLE_ID=gtest.$_output_name" ]
       }
     }
 
diff --git a/build/fuchsia/test_runner.py b/build/fuchsia/test_runner.py
index e2c832a8..20f1af35 100755
--- a/build/fuchsia/test_runner.py
+++ b/build/fuchsia/test_runner.py
@@ -101,7 +101,9 @@
 
 
 def BuildBootfs(output_directory, runtime_deps_path, test_name, gtest_filter,
-                gtest_repeat, test_launcher_filter_file, dry_run):
+                gtest_repeat, test_launcher_batch_limit,
+                test_launcher_filter_file, test_launcher_jobs,
+                single_process_tests, dry_run):
   with open(runtime_deps_path) as f:
     lines = f.readlines()
 
@@ -133,11 +135,14 @@
   autorun_file.write('#!/bin/sh\n')
   autorun_file.write('/system/' + os.path.basename(test_name))
   autorun_file.write(' --test-launcher-retry-limit=0')
+
   if int(os.environ.get('CHROME_HEADLESS', 0)) != 0:
     # When running on bots (without KVM) execution is quite slow. The test
     # launcher times out a subprocess after 45s which can be too short. Make the
     # timeout twice as long.
     autorun_file.write(' --test-launcher-timeout=90000')
+  if single_process_tests:
+    autorun_file.write(' --single-process-tests')
   if test_launcher_filter_file:
     test_launcher_filter_file = os.path.normpath(
             os.path.join(output_directory, test_launcher_filter_file))
@@ -147,6 +152,12 @@
                        filter_file_on_device)
     target_source_pairs.append(
         [filter_file_on_device, test_launcher_filter_file])
+  if test_launcher_batch_limit:
+    autorun_file.write(' --test-launcher-batch-limit=%d' %
+                       test_launcher_batch_limit)
+  if test_launcher_jobs:
+    autorun_file.write(' --test-launcher-jobs=%d' %
+                       test_launcher_jobs)
   if gtest_filter:
     autorun_file.write(' --gtest_filter=' + gtest_filter)
   if gtest_repeat:
@@ -210,18 +221,32 @@
                       type=os.path.realpath,
                       help='Name of the the test')
   parser.add_argument('--gtest_filter',
-                      help='GTest filter to use in place of any default')
+                      help='GTest filter to use in place of any default.')
   parser.add_argument('--gtest_repeat',
-                      help='GTest repeat value to use')
+                      help='GTest repeat value to use.')
+  parser.add_argument('--single-process-tests', action='store_true',
+                      default=False,
+                      help='Runs the tests and the launcher in the same '
+                      'process. Useful for debugging.')
+  parser.add_argument('--test-launcher-batch-limit',
+                      type=int,
+                      help='Sets the limit of test batch to run in a single '
+                      'process.')
   parser.add_argument('--test-launcher-filter-file',
-                      help='Pass filter file through to target process')
+                      type=os.path.realpath,
+                      help='Pass filter file through to target process.')
+  parser.add_argument('--test-launcher-jobs',
+                      type=int,
+                      help='Sets the number of parallel test jobs.')
   parser.add_argument('--test_launcher_summary_output',
                       help='Currently ignored for 2-sided roll.')
   args = parser.parse_args()
 
   bootfs = BuildBootfs(args.output_directory, args.runtime_deps_path,
                        args.test_name, args.gtest_filter, args.gtest_repeat,
-                       args.test_launcher_filter_file, args.dry_run)
+                       args.test_launcher_batch_limit,
+                       args.test_launcher_filter_file, args.test_launcher_jobs,
+                       args.single_process_tests, args.dry_run)
 
   qemu_path = os.path.join(SDK_ROOT, 'qemu', 'bin', 'qemu-system-x86_64')
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 2fe2405d..eb95eda 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,17 +293,12 @@
     "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",
     "resources/scoped_resource.h",
     "resources/scoped_ui_resource.cc",
     "resources/scoped_ui_resource.h",
-    "resources/shared_bitmap.cc",
-    "resources/shared_bitmap.h",
-    "resources/shared_bitmap_manager.h",
     "resources/single_release_callback.cc",
     "resources/single_release_callback.h",
     "resources/single_release_callback_impl.cc",
@@ -682,6 +675,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 +756,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/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 73e48a4..3e137fe 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -132,7 +132,7 @@
                     const gpu::SyncToken& sync_token,
                     bool lost_resource));
   MOCK_METHOD3(Release2,
-               void(SharedBitmap* shared_bitmap,
+               void(viz::SharedBitmap* shared_bitmap,
                     const gpu::SyncToken& sync_token,
                     bool lost_resource));
   MOCK_METHOD4(ReleaseImpl,
@@ -141,14 +141,14 @@
                     bool lost_resource,
                     BlockingTaskRunner* main_thread_task_runner));
   MOCK_METHOD4(ReleaseImpl2,
-               void(SharedBitmap* shared_bitmap,
+               void(viz::SharedBitmap* shared_bitmap,
                     const gpu::SyncToken& sync_token,
                     bool lost_resource,
                     BlockingTaskRunner* main_thread_task_runner));
 };
 
 struct CommonMailboxObjects {
-  explicit CommonMailboxObjects(SharedBitmapManager* manager)
+  explicit CommonMailboxObjects(viz::SharedBitmapManager* manager)
       : mailbox_name1_(MailboxFromChar('1')),
         mailbox_name2_(MailboxFromChar('2')),
         sync_token1_(gpu::CommandBufferNamespace::GPU_IO,
@@ -201,7 +201,7 @@
   TextureMailbox mailbox3_;
   gpu::SyncToken sync_token1_;
   gpu::SyncToken sync_token2_;
-  std::unique_ptr<SharedBitmap> shared_bitmap_;
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap_;
 };
 
 class TextureLayerTest : public testing::Test {
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index f5802441..3e35f72 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -418,7 +418,7 @@
   RendererSettings settings_;
   FakeOutputSurfaceClient output_surface_client_;
   std::unique_ptr<FakeOutputSurface> output_surface_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<FakeRendererGL> renderer_;
 };
@@ -529,7 +529,7 @@
   RendererSettings settings_;
   FakeOutputSurfaceClient output_surface_client_;
   std::unique_ptr<FakeOutputSurface> output_surface_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<FakeRendererGL> renderer_;
 };
@@ -658,7 +658,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -694,7 +694,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -728,7 +728,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -772,7 +772,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -809,7 +809,7 @@
       FakeOutputSurface::CreateOffscreen(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -868,7 +868,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -952,7 +952,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -1040,7 +1040,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -1115,7 +1115,7 @@
   auto output_surface = FakeOutputSurface::Create3d(std::move(provider));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -1215,7 +1215,7 @@
   RendererSettings settings_;
   FakeOutputSurfaceClient output_surface_client_;
   std::unique_ptr<FakeOutputSurface> output_surface_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<FakeRendererGL> renderer_;
 };
@@ -1287,7 +1287,7 @@
       FakeOutputSurface::Create3d());
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -1697,7 +1697,7 @@
   FakeOutputSurfaceClient output_surface_client_;
   OutputSurfaceMockContext* context_ = nullptr;
   std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<FakeRendererGL> renderer_;
 };
@@ -1767,7 +1767,7 @@
       FakeOutputSurface::Create3d());
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
@@ -1932,7 +1932,7 @@
       FakeOutputSurface::Create3d(std::move(provider)));
   output_surface->BindToClient(&output_surface_client);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(output_surface->context_provider(),
diff --git a/cc/output/layer_tree_frame_sink.cc b/cc/output/layer_tree_frame_sink.cc
index fedee969..6ad8324 100644
--- a/cc/output/layer_tree_frame_sink.cc
+++ b/cc/output/layer_tree_frame_sink.cc
@@ -22,7 +22,7 @@
     scoped_refptr<ContextProvider> context_provider,
     scoped_refptr<ContextProvider> worker_context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    SharedBitmapManager* shared_bitmap_manager)
+    viz::SharedBitmapManager* shared_bitmap_manager)
     : context_provider_(std::move(context_provider)),
       worker_context_provider_(std::move(worker_context_provider)),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
diff --git a/cc/output/layer_tree_frame_sink.h b/cc/output/layer_tree_frame_sink.h
index 94d8231..e953ce31 100644
--- a/cc/output/layer_tree_frame_sink.h
+++ b/cc/output/layer_tree_frame_sink.h
@@ -23,13 +23,16 @@
 class GpuMemoryBufferManager;
 }
 
+namespace viz {
+class SharedBitmapManager;
+}
+
 namespace cc {
 
 struct BeginFrameAck;
 class CompositorFrame;
 class LayerTreeFrameSinkClient;
 class LocalSurfaceId;
-class SharedBitmapManager;
 
 // An interface for submitting CompositorFrames to a display compositor
 // which will compose frames from multiple clients to show on screen to the
@@ -64,7 +67,7 @@
   LayerTreeFrameSink(scoped_refptr<ContextProvider> context_provider,
                      scoped_refptr<ContextProvider> worker_context_provider,
                      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-                     SharedBitmapManager* shared_bitmap_manager);
+                     viz::SharedBitmapManager* shared_bitmap_manager);
 
   // Constructor for Vulkan-based resources.
   explicit LayerTreeFrameSink(
@@ -103,7 +106,7 @@
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() const {
     return gpu_memory_buffer_manager_;
   }
-  SharedBitmapManager* shared_bitmap_manager() const {
+  viz::SharedBitmapManager* shared_bitmap_manager() const {
     return shared_bitmap_manager_;
   }
 
@@ -137,7 +140,7 @@
   scoped_refptr<ContextProvider> worker_context_provider_;
   scoped_refptr<VulkanContextProvider> vulkan_context_provider_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
-  SharedBitmapManager* shared_bitmap_manager_;
+  viz::SharedBitmapManager* shared_bitmap_manager_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LayerTreeFrameSink);
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 218ed8b54..35f3addf 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -448,7 +448,7 @@
   scoped_refptr<TestContextProvider> provider_;
   std::unique_ptr<OutputSurfaceType> output_surface_;
   FakeOutputSurfaceClient client_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<OverlayProcessor> overlay_processor_;
   gfx::Rect damage_rect_;
@@ -479,7 +479,7 @@
   output_surface.BindToClient(&client);
   output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator);
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(provider.get(), shared_bitmap_manager.get());
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/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index ec53b2d..3dce9d3 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -85,7 +85,7 @@
   RendererSettings settings_;
   FakeOutputSurfaceClient output_surface_client_;
   std::unique_ptr<FakeOutputSurface> output_surface_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<SoftwareRenderer> renderer_;
 };
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_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index a25ab1f..d445f07 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -41,7 +41,7 @@
   }
 
   scoped_refptr<TestContextProvider> context_provider_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   std::unique_ptr<ResourcePool> resource_pool_;
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index d4feafe..15e23df 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -24,9 +24,9 @@
 #include "base/trace_event/trace_event.h"
 #include "cc/resources/resource_util.h"
 #include "cc/resources/returned_resource.h"
-#include "cc/resources/shared_bitmap_manager.h"
 #include "cc/resources/transferable_resource.h"
 #include "components/viz/common/resources/platform_color.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -226,7 +226,7 @@
 }
 
 ResourceProvider::Resource::Resource(uint8_t* pixels,
-                                     SharedBitmap* bitmap,
+                                     viz::SharedBitmap* bitmap,
                                      const gfx::Size& size,
                                      Origin origin,
                                      GLenum filter)
@@ -269,7 +269,7 @@
     shared_bitmap_id = bitmap->id();
 }
 
-ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
+ResourceProvider::Resource::Resource(const viz::SharedBitmapId& bitmap_id,
                                      const gfx::Size& size,
                                      Origin origin,
                                      GLenum filter)
@@ -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),
@@ -411,12 +411,12 @@
 
 ResourceProvider::ResourceProvider(
     ContextProvider* compositor_context_provider,
-    SharedBitmapManager* shared_bitmap_manager,
+    viz::SharedBitmapManager* shared_bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     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,
@@ -649,7 +649,7 @@
                                           const gfx::ColorSpace& color_space) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  std::unique_ptr<SharedBitmap> bitmap =
+  std::unique_ptr<viz::SharedBitmap> bitmap =
       shared_bitmap_manager_->AllocateSharedBitmap(size);
   uint8_t* pixels = bitmap->pixels();
   DCHECK(pixels);
@@ -681,7 +681,7 @@
                      viz::RGBA_8888));
   } else {
     DCHECK(mailbox.IsSharedMemory());
-    SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
+    viz::SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
     uint8_t* pixels = shared_bitmap->pixels();
     DCHECK(pixels);
     resource = InsertResource(
@@ -978,7 +978,7 @@
 
   if (!resource->pixels && resource->has_shared_bitmap_id &&
       shared_bitmap_manager_) {
-    std::unique_ptr<SharedBitmap> bitmap =
+    std::unique_ptr<viz::SharedBitmap> bitmap =
         shared_bitmap_manager_->GetSharedBitmapFromId(
             resource->size, resource->shared_bitmap_id);
     if (bitmap) {
@@ -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;
 }
@@ -2123,7 +2123,7 @@
         break;
       case RESOURCE_TYPE_BITMAP:
         DCHECK(resource.has_shared_bitmap_id);
-        guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id);
+        guid = viz::GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id);
         if (resource.shared_bitmap) {
           shared_memory_guid =
               resource.shared_bitmap->GetSharedMemoryHandle().GetGUID();
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 49b27250..c4202e9 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/quads/shared_bitmap.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"
@@ -52,10 +52,13 @@
 }
 }
 
-namespace cc {
-class BlockingTaskRunner;
+namespace viz {
 class SharedBitmap;
 class SharedBitmapManager;
+}  // namespace viz
+
+namespace cc {
+class BlockingTaskRunner;
 class TextureIdAllocator;
 
 // This class is not thread-safe and can only be called from the thread it was
@@ -82,12 +85,12 @@
   };
 
   ResourceProvider(ContextProvider* compositor_context_provider,
-                   SharedBitmapManager* shared_bitmap_manager,
+                   viz::SharedBitmapManager* shared_bitmap_manager,
                    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
                    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();
@@ -590,11 +593,11 @@
              ResourceType type,
              viz::ResourceFormat format);
     Resource(uint8_t* pixels,
-             SharedBitmap* bitmap,
+             viz::SharedBitmap* bitmap,
              const gfx::Size& size,
              Origin origin,
              GLenum filter);
-    Resource(const SharedBitmapId& bitmap_id,
+    Resource(const viz::SharedBitmapId& bitmap_id,
              const gfx::Size& size,
              Origin origin,
              GLenum filter);
@@ -677,8 +680,8 @@
     // correspond to buffer_format (e.g: A resouce that was created from a YUV
     // buffer could be seen as RGB from the compositor/GL.)
     viz::ResourceFormat format;
-    SharedBitmapId shared_bitmap_id;
-    SharedBitmap* shared_bitmap;
+    viz::SharedBitmapId shared_bitmap_id;
+    viz::SharedBitmap* shared_bitmap;
     std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
     gfx::ColorSpace color_space;
 
@@ -766,7 +769,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;
@@ -783,7 +786,7 @@
   } const settings_;
 
   ContextProvider* compositor_context_provider_;
-  SharedBitmapManager* shared_bitmap_manager_;
+  viz::SharedBitmapManager* shared_bitmap_manager_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
   BlockingTaskRunner* blocking_main_thread_task_runner_;
   bool lost_context_provider_;
@@ -793,7 +796,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..0e8ddc5af 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -18,9 +18,7 @@
 #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"
 #include "cc/test/test_context_provider.h"
 #include "cc/test/test_gpu_memory_buffer_manager.h"
@@ -28,7 +26,9 @@
 #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 "components/viz/common/resources/shared_bitmap_manager.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,13 +73,13 @@
 }
 
 static void SharedBitmapReleaseCallback(
-    std::unique_ptr<SharedBitmap> bitmap,
+    std::unique_ptr<viz::SharedBitmap> bitmap,
     const gpu::SyncToken& sync_token,
     bool lost_resource,
     BlockingTaskRunner* main_thread_task_runner) {}
 
 static void ReleaseSharedBitmapCallback(
-    std::unique_ptr<SharedBitmap> shared_bitmap,
+    std::unique_ptr<viz::SharedBitmap> shared_bitmap,
     bool* release_called,
     gpu::SyncToken* release_sync_token,
     bool* lost_resource_result,
@@ -91,11 +91,11 @@
   *lost_resource_result = lost_resource;
 }
 
-static std::unique_ptr<SharedBitmap> CreateAndFillSharedBitmap(
-    SharedBitmapManager* manager,
+static std::unique_ptr<viz::SharedBitmap> CreateAndFillSharedBitmap(
+    viz::SharedBitmapManager* manager,
     const gfx::Size& size,
     uint32_t value) {
-  std::unique_ptr<SharedBitmap> shared_bitmap =
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap =
       manager->AllocateSharedBitmap(size);
   CHECK(shared_bitmap);
   uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
@@ -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(),
@@ -511,7 +511,7 @@
                                    sync_token->GetData());
       EXPECT_TRUE(sync_token->HasData());
 
-      std::unique_ptr<SharedBitmap> shared_bitmap;
+      std::unique_ptr<viz::SharedBitmap> shared_bitmap;
       std::unique_ptr<SingleReleaseCallbackImpl> callback =
           SingleReleaseCallbackImpl::Create(base::Bind(
               ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
@@ -521,10 +521,10 @@
           std::move(callback));
     } else {
       gfx::Size size(64, 64);
-      std::unique_ptr<SharedBitmap> shared_bitmap(
+      std::unique_ptr<viz::SharedBitmap> shared_bitmap(
           CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, 0));
 
-      SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
+      viz::SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
       std::unique_ptr<SingleReleaseCallbackImpl> callback =
           SingleReleaseCallbackImpl::Create(base::Bind(
               ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
@@ -1421,9 +1421,9 @@
   uint8_t data2[4] = { 5, 5, 5, 5 };
   child_resource_provider_->CopyToResource(id2, data2, size);
 
-  std::unique_ptr<SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
       shared_bitmap_manager_.get(), gfx::Size(1, 1), 0));
-  SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
+  viz::SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
   ResourceId id3 = child_resource_provider_->CreateResourceFromTextureMailbox(
       TextureMailbox(shared_bitmap_ptr, gfx::Size(1, 1)),
       SingleReleaseCallbackImpl::Create(base::Bind(
@@ -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,
@@ -2970,7 +2970,7 @@
 
   gfx::Size size(64, 64);
   const uint32_t kBadBeef = 0xbadbeef;
-  std::unique_ptr<SharedBitmap> shared_bitmap(
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap(
       CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, kBadBeef));
 
   std::unique_ptr<ResourceProvider> resource_provider(
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index cbfbe68..ca76b41d 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -19,7 +19,7 @@
       TestContextProvider::Create();
   ASSERT_TRUE(context_provider->BindToCurrentThread());
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(context_provider.get(),
@@ -40,7 +40,7 @@
       TestContextProvider::Create();
   ASSERT_TRUE(context_provider->BindToCurrentThread());
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(context_provider.get(),
@@ -64,7 +64,7 @@
       TestContextProvider::Create();
   ASSERT_TRUE(context_provider->BindToCurrentThread());
 
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager(
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
   std::unique_ptr<ResourceProvider> resource_provider =
       FakeResourceProvider::Create(context_provider.get(),
diff --git a/cc/resources/texture_mailbox.cc b/cc/resources/texture_mailbox.cc
index c79ee62..468624d 100644
--- a/cc/resources/texture_mailbox.cc
+++ b/cc/resources/texture_mailbox.cc
@@ -8,7 +8,7 @@
 #include <stdint.h>
 
 #include "base/logging.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 
 namespace cc {
 
@@ -62,7 +62,7 @@
   DCHECK(!is_overlay_candidate || !size_in_pixels.IsEmpty());
 }
 
-TextureMailbox::TextureMailbox(SharedBitmap* shared_bitmap,
+TextureMailbox::TextureMailbox(viz::SharedBitmap* shared_bitmap,
                                const gfx::Size& size_in_pixels)
     : shared_bitmap_(shared_bitmap),
       size_in_pixels_(size_in_pixels),
@@ -75,7 +75,7 @@
       nearest_neighbor_(false) {
   // If an embedder of cc gives an invalid TextureMailbox, we should crash
   // here to identify the offender.
-  CHECK(SharedBitmap::VerifySizeInBytes(size_in_pixels_));
+  CHECK(viz::SharedBitmap::VerifySizeInBytes(size_in_pixels_));
 }
 
 TextureMailbox::~TextureMailbox() {}
@@ -96,7 +96,7 @@
 size_t TextureMailbox::SharedMemorySizeInBytes() const {
   // UncheckedSizeInBytes is okay because we VerifySizeInBytes in the
   // constructor and the field is immutable.
-  return SharedBitmap::UncheckedSizeInBytes(size_in_pixels_);
+  return viz::SharedBitmap::UncheckedSizeInBytes(size_in_pixels_);
 }
 
 }  // namespace cc
diff --git a/cc/resources/texture_mailbox.h b/cc/resources/texture_mailbox.h
index ee86471..4380135 100644
--- a/cc/resources/texture_mailbox.h
+++ b/cc/resources/texture_mailbox.h
@@ -17,14 +17,16 @@
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 
+namespace viz {
+class SharedBitmap;
+}
+
 namespace cc {
 
 namespace mojom {
 class TextureMailboxDataView;
 }
 
-class SharedBitmap;
-
 // TODO(skaslev, danakj) Rename this class more apropriately since now it
 // can hold a shared memory resource as well as a texture mailbox.
 class CC_EXPORT TextureMailbox {
@@ -41,7 +43,8 @@
                  const gfx::Size& size_in_pixels,
                  bool is_overlay_candidate,
                  bool secure_output_only);
-  TextureMailbox(SharedBitmap* shared_bitmap, const gfx::Size& size_in_pixels);
+  TextureMailbox(viz::SharedBitmap* shared_bitmap,
+                 const gfx::Size& size_in_pixels);
 
   ~TextureMailbox();
 
@@ -81,7 +84,7 @@
   // This is valid if allow_overlau() or IsSharedMemory() is true.
   gfx::Size size_in_pixels() const { return size_in_pixels_; }
 
-  SharedBitmap* shared_bitmap() const { return shared_bitmap_; }
+  viz::SharedBitmap* shared_bitmap() const { return shared_bitmap_; }
   size_t SharedMemorySizeInBytes() const;
 
 #if defined(OS_ANDROID)
@@ -103,7 +106,7 @@
                                    TextureMailbox>;
 
   gpu::MailboxHolder mailbox_holder_;
-  SharedBitmap* shared_bitmap_;
+  viz::SharedBitmap* shared_bitmap_;
   gfx::Size size_in_pixels_;
   bool is_overlay_candidate_;
 #if defined(OS_ANDROID)
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 135d1445..17ec9e43 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -77,7 +77,7 @@
 
 class SharedBitmapManagerAllocationCounter : public TestSharedBitmapManager {
  public:
-  std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
+  std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
       const gfx::Size& size) override {
     ++allocation_count_;
     return TestSharedBitmapManager::AllocateSharedBitmap(size);
diff --git a/cc/surfaces/direct_layer_tree_frame_sink.cc b/cc/surfaces/direct_layer_tree_frame_sink.cc
index 1b57532..f81c5a6 100644
--- a/cc/surfaces/direct_layer_tree_frame_sink.cc
+++ b/cc/surfaces/direct_layer_tree_frame_sink.cc
@@ -22,7 +22,7 @@
     scoped_refptr<ContextProvider> context_provider,
     scoped_refptr<ContextProvider> worker_context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    SharedBitmapManager* shared_bitmap_manager)
+    viz::SharedBitmapManager* shared_bitmap_manager)
     : LayerTreeFrameSink(std::move(context_provider),
                          std::move(worker_context_provider),
                          gpu_memory_buffer_manager,
diff --git a/cc/surfaces/direct_layer_tree_frame_sink.h b/cc/surfaces/direct_layer_tree_frame_sink.h
index b1bcaf5..c9dd7b10 100644
--- a/cc/surfaces/direct_layer_tree_frame_sink.h
+++ b/cc/surfaces/direct_layer_tree_frame_sink.h
@@ -37,7 +37,7 @@
       scoped_refptr<ContextProvider> context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      SharedBitmapManager* shared_bitmap_manager);
+      viz::SharedBitmapManager* shared_bitmap_manager);
   DirectLayerTreeFrameSink(
       const FrameSinkId& frame_sink_id,
       FrameSinkManager* frame_sink_manager,
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index ead51b6..831aa9a 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -33,7 +33,7 @@
 
 namespace cc {
 
-Display::Display(SharedBitmapManager* bitmap_manager,
+Display::Display(viz::SharedBitmapManager* bitmap_manager,
                  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
                  const RendererSettings& settings,
                  const FrameSinkId& frame_sink_id,
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 428b241..0a39ef5 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -30,6 +30,10 @@
 class Size;
 }
 
+namespace viz {
+class SharedBitmapManager;
+}
+
 namespace cc {
 
 class DirectRenderer;
@@ -37,7 +41,6 @@
 class OutputSurface;
 class RendererSettings;
 class ResourceProvider;
-class SharedBitmapManager;
 class SoftwareRenderer;
 class TextureMailboxDeleter;
 
@@ -49,7 +52,7 @@
  public:
   // The |begin_frame_source| and |scheduler| may be null (together). In that
   // case, DrawAndSwap must be called externally when needed.
-  Display(SharedBitmapManager* bitmap_manager,
+  Display(viz::SharedBitmapManager* bitmap_manager,
           gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
           const RendererSettings& settings,
           const FrameSinkId& frame_sink_id,
@@ -98,7 +101,7 @@
   void UpdateRootSurfaceResourcesLocked();
   void DidLoseContextProvider();
 
-  SharedBitmapManager* const bitmap_manager_;
+  viz::SharedBitmapManager* const bitmap_manager_;
   gpu::GpuMemoryBufferManager* const gpu_memory_buffer_manager_;
   const RendererSettings settings_;
 
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 5abeff7..62958f6 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -12,7 +12,6 @@
 #include "cc/output/copy_output_result.h"
 #include "cc/output/texture_mailbox_deleter.h"
 #include "cc/quads/render_pass.h"
-#include "cc/resources/shared_bitmap_manager.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/display_client.h"
@@ -26,6 +25,7 @@
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/scheduler_test_common.h"
 #include "cc/test/test_shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/cc/surfaces/surface_aggregator_perftest.cc b/cc/surfaces/surface_aggregator_perftest.cc
index 89ef0f9..a9c8a35 100644
--- a/cc/surfaces/surface_aggregator_perftest.cc
+++ b/cc/surfaces/surface_aggregator_perftest.cc
@@ -152,7 +152,7 @@
  protected:
   FrameSinkManager manager_;
   scoped_refptr<TestContextProvider> context_provider_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<SurfaceAggregator> aggregator_;
   LapTimer timer_;
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index fe1130fd..a89f1c3c 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -17,7 +17,6 @@
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
-#include "cc/resources/shared_bitmap_manager.h"
 #include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/frame_sink_manager.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
@@ -30,6 +29,7 @@
 #include "cc/test/render_pass_test_utils.h"
 #include "cc/test/surface_aggregator_test_helpers.h"
 #include "cc/test/test_shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -1963,7 +1963,7 @@
 
  protected:
   FrameSinkManager manager_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<SurfaceAggregator> aggregator_;
 };
diff --git a/cc/test/fake_resource_provider.h b/cc/test/fake_resource_provider.h
index fb46f1f..f8771fd5 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 {
@@ -18,11 +18,11 @@
  public:
   static std::unique_ptr<FakeResourceProvider> Create(
       ContextProvider* context_provider,
-      SharedBitmapManager* shared_bitmap_manager) {
-    ResourceSettings resource_settings;
+      viz::SharedBitmapManager* shared_bitmap_manager) {
+    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));
@@ -30,12 +30,12 @@
 
   static std::unique_ptr<FakeResourceProvider> Create(
       ContextProvider* context_provider,
-      SharedBitmapManager* shared_bitmap_manager,
+      viz::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));
@@ -43,12 +43,12 @@
 
  private:
   FakeResourceProvider(ContextProvider* context_provider,
-                       SharedBitmapManager* shared_bitmap_manager,
+                       viz::SharedBitmapManager* shared_bitmap_manager,
                        gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
                        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/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index e7c4644..6695daab 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -124,7 +124,7 @@
   bool TestEnded() const { return ended_; }
 
   LayerTreeHost* layer_tree_host();
-  SharedBitmapManager* shared_bitmap_manager() const {
+  viz::SharedBitmapManager* shared_bitmap_manager() const {
     return shared_bitmap_manager_.get();
   }
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() {
@@ -196,7 +196,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
   std::unique_ptr<base::Thread> impl_thread_;
   std::unique_ptr<base::Thread> image_worker_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   std::unique_ptr<TestTaskGraphRunner> task_graph_runner_;
   base::CancelableClosure timeout_;
diff --git a/cc/test/test_layer_tree_frame_sink.cc b/cc/test/test_layer_tree_frame_sink.cc
index 9e93c09..f671f4c 100644
--- a/cc/test/test_layer_tree_frame_sink.cc
+++ b/cc/test/test_layer_tree_frame_sink.cc
@@ -24,7 +24,7 @@
 TestLayerTreeFrameSink::TestLayerTreeFrameSink(
     scoped_refptr<ContextProvider> compositor_context_provider,
     scoped_refptr<ContextProvider> worker_context_provider,
-    SharedBitmapManager* shared_bitmap_manager,
+    viz::SharedBitmapManager* shared_bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const RendererSettings& renderer_settings,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
diff --git a/cc/test/test_layer_tree_frame_sink.h b/cc/test/test_layer_tree_frame_sink.h
index 8feb90a8..c877674 100644
--- a/cc/test/test_layer_tree_frame_sink.h
+++ b/cc/test/test_layer_tree_frame_sink.h
@@ -53,7 +53,7 @@
   TestLayerTreeFrameSink(
       scoped_refptr<ContextProvider> compositor_context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
-      SharedBitmapManager* shared_bitmap_manager,
+      viz::SharedBitmapManager* shared_bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& renderer_settings,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
diff --git a/cc/test/test_shared_bitmap_manager.cc b/cc/test/test_shared_bitmap_manager.cc
index ca4b50f..900aaaa 100644
--- a/cc/test/test_shared_bitmap_manager.cc
+++ b/cc/test/test_shared_bitmap_manager.cc
@@ -13,16 +13,16 @@
 
 namespace {
 
-class OwnedSharedBitmap : public SharedBitmap {
+class OwnedSharedBitmap : public viz::SharedBitmap {
  public:
   OwnedSharedBitmap(std::unique_ptr<base::SharedMemory> shared_memory,
-                    const SharedBitmapId& id)
-      : SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
+                    const viz::SharedBitmapId& id)
+      : viz::SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
         shared_memory_(std::move(shared_memory)) {}
 
   ~OwnedSharedBitmap() override {}
 
-  // SharedBitmap:
+  // viz::SharedBitmap:
   base::SharedMemoryHandle GetSharedMemoryHandle() const override {
     return shared_memory_->handle();
   }
@@ -31,12 +31,12 @@
   std::unique_ptr<base::SharedMemory> shared_memory_;
 };
 
-class UnownedSharedBitmap : public SharedBitmap {
+class UnownedSharedBitmap : public viz::SharedBitmap {
  public:
-  UnownedSharedBitmap(uint8_t* pixels, const SharedBitmapId& id)
-      : SharedBitmap(pixels, id) {}
+  UnownedSharedBitmap(uint8_t* pixels, const viz::SharedBitmapId& id)
+      : viz::SharedBitmap(pixels, id) {}
 
-  // SharedBitmap:
+  // viz::SharedBitmap:
   base::SharedMemoryHandle GetSharedMemoryHandle() const override {
     return base::SharedMemoryHandle();
   }
@@ -48,19 +48,19 @@
 
 TestSharedBitmapManager::~TestSharedBitmapManager() {}
 
-std::unique_ptr<SharedBitmap> TestSharedBitmapManager::AllocateSharedBitmap(
-    const gfx::Size& size) {
+std::unique_ptr<viz::SharedBitmap>
+TestSharedBitmapManager::AllocateSharedBitmap(const gfx::Size& size) {
   base::AutoLock lock(lock_);
   std::unique_ptr<base::SharedMemory> memory(new base::SharedMemory);
   memory->CreateAndMapAnonymous(size.GetArea() * 4);
-  SharedBitmapId id = SharedBitmap::GenerateId();
+  viz::SharedBitmapId id = viz::SharedBitmap::GenerateId();
   bitmap_map_[id] = memory.get();
   return base::MakeUnique<OwnedSharedBitmap>(std::move(memory), id);
 }
 
-std::unique_ptr<SharedBitmap> TestSharedBitmapManager::GetSharedBitmapFromId(
-    const gfx::Size&,
-    const SharedBitmapId& id) {
+std::unique_ptr<viz::SharedBitmap>
+TestSharedBitmapManager::GetSharedBitmapFromId(const gfx::Size&,
+                                               const viz::SharedBitmapId& id) {
   base::AutoLock lock(lock_);
   if (bitmap_map_.find(id) == bitmap_map_.end())
     return nullptr;
diff --git a/cc/test/test_shared_bitmap_manager.h b/cc/test/test_shared_bitmap_manager.h
index 912d03d..4cce36f 100644
--- a/cc/test/test_shared_bitmap_manager.h
+++ b/cc/test/test_shared_bitmap_manager.h
@@ -8,7 +8,7 @@
 #include <map>
 
 #include "base/synchronization/lock.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 
 namespace base {
 class SharedMemory;
@@ -16,21 +16,21 @@
 
 namespace cc {
 
-class TestSharedBitmapManager : public SharedBitmapManager {
+class TestSharedBitmapManager : public viz::SharedBitmapManager {
  public:
   TestSharedBitmapManager();
   ~TestSharedBitmapManager() override;
 
-  std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
+  std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
       const gfx::Size& size) override;
 
-  std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
+  std::unique_ptr<viz::SharedBitmap> GetSharedBitmapFromId(
       const gfx::Size&,
-      const SharedBitmapId& id) override;
+      const viz::SharedBitmapId& id) override;
 
  private:
   base::Lock lock_;
-  std::map<SharedBitmapId, base::SharedMemory*> bitmap_map_;
+  std::map<viz::SharedBitmapId, base::SharedMemory*> bitmap_map_;
 };
 
 }  // namespace cc
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/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 2cbb8cc..8a0ee43c 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -34,10 +34,6 @@
 namespace cc {
 namespace {
 
-// The largest single high quality image to try and process. Images above this
-// size will drop down to medium quality.
-const size_t kMaxHighQualityImageSizeBytes = 64 * 1024 * 1024;
-
 // The number of entries to keep around in the cache. This limit can be breached
 // if more items are locked. That is, locked items ignore this limit.
 // Depending on the memory state of the system, we limit the amount of items
@@ -454,8 +450,8 @@
         return GetSubrectImageDecode(key, draw_image.paint_image());
       return GetOriginalSizeImageDecode(key, std::move(image));
     case kMedium_SkFilterQuality:
-    case kHigh_SkFilterQuality:
       return GetScaledImageDecode(key, draw_image.paint_image());
+    case kHigh_SkFilterQuality:
     default:
       NOTREACHED();
       return nullptr;
@@ -736,8 +732,7 @@
   }
   SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(),
                          scaled_info.minRowBytes());
-  DCHECK(key.filter_quality() == kHigh_SkFilterQuality ||
-         key.filter_quality() == kMedium_SkFilterQuality);
+  DCHECK(key.filter_quality() == kMedium_SkFilterQuality);
   {
     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                  "SoftwareImageDecodeCache::ScaleImage - scale pixels");
@@ -928,62 +923,57 @@
   // Note that the scale is still unchanged and the target size is now a
   // function of the new src_rect.
   const gfx::Rect& src_rect = GetSrcRect(image);
+
+  // Start with the exact target size. However, this will be adjusted below to
+  // be either a mip level, the original size, or a subrect size. This is done
+  // to keep memory accounting correct.
   gfx::Size target_size(
       SkScalarRoundToInt(std::abs(src_rect.width() * scale.width())),
       SkScalarRoundToInt(std::abs(src_rect.height() * scale.height())));
 
-  // Start with the quality that was requested.
+  // If the target size is empty, then we'll be skipping the decode anyway, so
+  // the filter quality doesn't matter. Early out instead.
+  if (target_size.IsEmpty()) {
+    return ImageDecodeCacheKey(image.image()->uniqueID(), src_rect, target_size,
+                               image.target_color_space(), kLow_SkFilterQuality,
+                               true /* can_use_original_decode */,
+                               false /* should_use_subrect */);
+  }
+
+  // Start with the given filter quality.
   SkFilterQuality quality = image.filter_quality();
 
-  // If we're not going to do a scale, we can use low filter quality. Note that
-  // checking if the sizes are the same is better than checking if scale is 1.f,
-  // because even non-1 scale can result in the same (rounded) width/height.
-  // If either dimension is a downscale, and the quality is not None (in which
-  // case we need to preserve the pixelated scale), then use mipmaps (medium
-  // filter quality).
-  if (target_size.width() == src_rect.width() &&
-      target_size.height() == src_rect.height()) {
+  int mip_level = MipMapUtil::GetLevelForSize(src_rect.size(), target_size);
+  // If any of the following conditions hold, then use at most low filter
+  // quality and adjust the target size to match the original image:
+  // - Quality is none: We need a pixelated image, so we can't upgrade it.
+  // - Format is RGBA_4444: Skia doesn't support scaling these, so use low
+  //   filter quality.
+  // - Mip level is 0: The required mip is the original image, so just use low
+  //   filter quality.
+  // - Matrix is not decomposable: There's perspective on this image and we
+  //   can't determine the size, so use the original.
+  if (quality == kNone_SkFilterQuality || format == viz::RGBA_4444 ||
+      mip_level == 0 || !image.matrix_is_decomposable()) {
     quality = std::min(quality, kLow_SkFilterQuality);
-  } else if (quality != kNone_SkFilterQuality &&
-             (target_size.width() < src_rect.width() ||
-              target_size.height() < src_rect.height())) {
+    // Update the size to be the original image size.
+    target_size = gfx::Size(image.image()->width(), image.image()->height());
+  } else {
     quality = kMedium_SkFilterQuality;
+    // Update the target size to be a mip level size.
+    SkSize mip_scale_adjustment =
+        MipMapUtil::GetScaleAdjustmentForLevel(src_rect.size(), mip_level);
+    target_size.set_width(src_rect.width() * mip_scale_adjustment.width());
+    target_size.set_height(src_rect.height() * mip_scale_adjustment.height());
   }
 
-  // Skia doesn't scale an viz::RGBA_4444 format, so always use the original
-  // decode.
-  if (format == viz::RGBA_4444)
-    quality = std::min(quality, kLow_SkFilterQuality);
-
-  // Drop from high to medium if the the matrix we applied wasn't decomposable,
-  // or if the scaled image will be too large.
-  if (quality == kHigh_SkFilterQuality) {
-    if (!image.matrix_is_decomposable()) {
-      quality = kMedium_SkFilterQuality;
-    } else {
-      base::CheckedNumeric<size_t> size = 4u;
-      size *= target_size.width();
-      size *= target_size.height();
-      if (size.ValueOrDefault(std::numeric_limits<size_t>::max()) >
-          kMaxHighQualityImageSizeBytes) {
-        quality = kMedium_SkFilterQuality;
-      }
-    }
-  }
-
-  // Drop from medium to low if the matrix we applied wasn't decomposable or if
-  // we're enlarging the image in both dimensions.
-  if (quality == kMedium_SkFilterQuality) {
-    if (!image.matrix_is_decomposable() ||
-        (scale.width() >= 1.f && scale.height() >= 1.f)) {
-      quality = kLow_SkFilterQuality;
-    }
-  }
-
+  // Now the quality is fixed, determine the other parameters we need.
   bool can_use_original_size_decode =
       quality == kLow_SkFilterQuality || quality == kNone_SkFilterQuality;
-
   bool should_use_subrect = false;
+
+  // If the original image is large, we might want to do a subrect instead if
+  // the subrect would be kMemoryRatioToSubrect times smaller.
   if (can_use_original_size_decode &&
       (image.image()->width() >= kMinDimensionToSubrect ||
        image.image()->height() >= kMinDimensionToSubrect)) {
@@ -998,29 +988,16 @@
     checked_src_rect_size *= src_rect.height();
     size_t src_rect_size = checked_src_rect_size.ValueOrDefault(
         std::numeric_limits<size_t>::max());
+
+    // If the sizes are such that we get good savings by subrecting, then do
+    // that. Also update the target size to be the src rect size since that's
+    // the rect we want to use.
     if (original_size > kMemoryThresholdToSubrect &&
         src_rect_size <= original_size * kMemoryRatioToSubrect) {
       should_use_subrect = true;
       can_use_original_size_decode = false;
-    }
-  }
-
-  // If we're going to use the original decode, then the target size should be
-  // the full image size, since that will allow for proper memory accounting.
-  // Note we skip the decode if the target size is empty altogether, so don't
-  // update the target size in that case.
-  if (!target_size.IsEmpty()) {
-    if (should_use_subrect)
       target_size = src_rect.size();
-    else if (can_use_original_size_decode)
-      target_size = gfx::Size(image.image()->width(), image.image()->height());
-  }
-
-  if (quality == kMedium_SkFilterQuality && !target_size.IsEmpty()) {
-    SkSize mip_target_size =
-        MipMapUtil::GetScaleAdjustmentForSize(src_rect.size(), target_size);
-    target_size.set_width(src_rect.width() * mip_target_size.width());
-    target_size.set_height(src_rect.height() * mip_target_size.height());
+    }
   }
 
   return ImageDecodeCacheKey(image.image()->uniqueID(), src_rect, target_size,
diff --git a/cc/tiles/software_image_decode_cache_unittest.cc b/cc/tiles/software_image_decode_cache_unittest.cc
index 9d3560e..8b67f4b 100644
--- a/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/cc/tiles/software_image_decode_cache_unittest.cc
@@ -83,15 +83,33 @@
   DrawImage draw_image(CreatePaintImage(image),
                        SkIRect::MakeWH(image->width(), image->height()),
                        kLow_SkFilterQuality,
-                       CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+                       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
 
   auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
   EXPECT_EQ(image->uniqueID(), key.image_id());
   EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
+  EXPECT_EQ(50, key.target_size().width());
+  EXPECT_EQ(50, key.target_size().height());
+  EXPECT_FALSE(key.can_use_original_size_decode());
+  EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
+}
+
+TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropsToLowIfMipLevel0) {
+  sk_sp<SkImage> image = CreateImage(100, 100);
+  bool is_decomposable = true;
+  DrawImage draw_image(
+      CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+      kMedium_SkFilterQuality,
+      CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
+      DefaultColorSpace());
+
+  auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
+  EXPECT_EQ(image->uniqueID(), key.image_id());
+  EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
   EXPECT_EQ(100, key.target_size().width());
   EXPECT_EQ(100, key.target_size().height());
-  EXPECT_FALSE(key.can_use_original_size_decode());
+  EXPECT_TRUE(key.can_use_original_size_decode());
   EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
 }
 
@@ -156,16 +174,16 @@
 
   DrawImage draw_image(
       CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
-      quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+      quality, CreateMatrix(SkSize::Make(0.5f, 0.4f), is_decomposable),
       DefaultColorSpace());
 
   auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
   EXPECT_EQ(image->uniqueID(), key.image_id());
   EXPECT_EQ(quality, key.filter_quality());
-  EXPECT_EQ(100, key.target_size().width());
-  EXPECT_EQ(100, key.target_size().height());
+  EXPECT_EQ(50, key.target_size().width());
+  EXPECT_EQ(50, key.target_size().height());
   EXPECT_FALSE(key.can_use_original_size_decode());
-  EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
+  EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
 }
 
 TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) {
@@ -304,7 +322,7 @@
   EXPECT_EQ(500u * 200u * 4u, key.locked_bytes());
 }
 
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_75Scale) {
+TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) {
   sk_sp<SkImage> image = CreateImage(500, 200);
   bool is_decomposable = true;
   SkFilterQuality quality = kMedium_SkFilterQuality;
@@ -316,10 +334,10 @@
 
   auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
   EXPECT_EQ(image->uniqueID(), key.image_id());
-  EXPECT_EQ(quality, key.filter_quality());
+  EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
   EXPECT_EQ(500, key.target_size().width());
   EXPECT_EQ(200, key.target_size().height());
-  EXPECT_FALSE(key.can_use_original_size_decode());
+  EXPECT_TRUE(key.can_use_original_size_decode());
   EXPECT_EQ(500u * 200u * 4u, key.locked_bytes());
 }
 
@@ -400,26 +418,6 @@
 }
 
 TEST(SoftwareImageDecodeCacheTest,
-     ImageKeyPartialDowscalesDropsHighQualityToMedium) {
-  sk_sp<SkImage> image = CreateImage(100, 100);
-  bool is_decomposable = true;
-  SkFilterQuality quality = kHigh_SkFilterQuality;
-
-  DrawImage draw_image(
-      CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
-      quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
-      DefaultColorSpace());
-
-  auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
-  EXPECT_EQ(image->uniqueID(), key.image_id());
-  EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
-  EXPECT_EQ(100, key.target_size().width());
-  EXPECT_EQ(100, key.target_size().height());
-  EXPECT_FALSE(key.can_use_original_size_decode());
-  EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
-}
-
-TEST(SoftwareImageDecodeCacheTest,
      ImageKeyFullDowscalesDropsHighQualityToMedium) {
   sk_sp<SkImage> image = CreateImage(100, 100);
   bool is_decomposable = true;
@@ -439,7 +437,7 @@
   EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
 }
 
-TEST(SoftwareImageDecodeCacheTest, ImageKeyDowscalesHighQuality) {
+TEST(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) {
   sk_sp<SkImage> image = CreateImage(100, 100);
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
@@ -451,11 +449,11 @@
 
   auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
   EXPECT_EQ(image->uniqueID(), key.image_id());
-  EXPECT_EQ(quality, key.filter_quality());
-  EXPECT_EQ(250, key.target_size().width());
-  EXPECT_EQ(150, key.target_size().height());
-  EXPECT_FALSE(key.can_use_original_size_decode());
-  EXPECT_EQ(250u * 150u * 4u, key.locked_bytes());
+  EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
+  EXPECT_EQ(100, key.target_size().width());
+  EXPECT_EQ(100, key.target_size().height());
+  EXPECT_TRUE(key.can_use_original_size_decode());
+  EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
 }
 
 TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) {
@@ -468,16 +466,16 @@
   // become low.
   DrawImage draw_image(
       CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
-      quality, CreateMatrix(SkSize::Make(0.9f, 2.f), is_decomposable),
+      quality, CreateMatrix(SkSize::Make(0.45f, 0.45f), is_decomposable),
       DefaultColorSpace());
 
   auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, viz::RGBA_8888);
   EXPECT_EQ(image->uniqueID(), key.image_id());
   EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
-  EXPECT_EQ(4555, key.target_size().width());
-  EXPECT_EQ(2048, key.target_size().height());
+  EXPECT_EQ(2277, key.target_size().width());
+  EXPECT_EQ(1024, key.target_size().height());
   EXPECT_FALSE(key.can_use_original_size_decode());
-  EXPECT_EQ(4555u * 2048u * 4u, key.locked_bytes());
+  EXPECT_EQ(2277u * 1024u * 4u, key.locked_bytes());
 }
 
 TEST(SoftwareImageDecodeCacheTest,
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_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index f69d8fc..b64406d3 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3362,10 +3362,10 @@
 
 class OnDrawLayerTreeFrameSink : public TestLayerTreeFrameSink {
  public:
-  explicit OnDrawLayerTreeFrameSink(
+  OnDrawLayerTreeFrameSink(
       scoped_refptr<ContextProvider> compositor_context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
-      SharedBitmapManager* shared_bitmap_manager,
+      viz::SharedBitmapManager* shared_bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& renderer_settings,
       base::SingleThreadTaskRunner* task_runner,
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 55b84af..250cb10 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -1041,7 +1041,7 @@
   bool lost_context_;
 
   scoped_refptr<TestContextProvider> child_context_provider_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
+  std::unique_ptr<viz::SharedBitmapManager> shared_bitmap_manager_;
   std::unique_ptr<ResourceProvider> child_resource_provider_;
 
   scoped_refptr<VideoFrame> color_video_frame_;
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 e65cd755..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/VERSION b/chrome/VERSION
index 1bb73ad..4d1936a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3154
+BUILD=3155
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c59688c1..9bdf03fa 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -319,7 +319,6 @@
     "//chrome/browser/android/policy/policy_auditor.cc",
     "//chrome/browser/android/shortcut_info.h",
     "//chrome/browser/android/tab_android.h",
-    "//chrome/browser/android/webapk/chrome_webapk_host.h",
     "//chrome/browser/android/webapk/webapk_install_service.h",
     "//chrome/browser/banners/app_banner_settings_helper.h",
     "//chrome/browser/notifications/notification_channels_provider_android.h",
@@ -861,6 +860,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/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index f243f11..2c0c3b0 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -260,6 +260,7 @@
             <meta-data android:name="android.app.shortcuts"
                 android:resource="@xml/launchershortcuts" />
 
+            {{ self.supports_vr() }}
         </activity-alias>
 
         <activity android:name="org.chromium.chrome.browser.LauncherShortcutActivity"
@@ -394,7 +395,7 @@
             android:exported="false"
             {{ self.chrome_activity_common() }}>
         </activity>
-        <activity android:name="org.chromium.chrome.browser.FullscreenWebContentsActivity"
+        <activity android:name="org.chromium.chrome.browser.FullscreenActivity"
             android:theme="@style/MainTheme"
             android:exported="false"
             android:noHistory="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..cd5a77fd
--- /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/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 09c67660..437ac49 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -23,6 +23,7 @@
         <item name="android:textColorHighlight">@color/text_highlight_color</item>
         <item name="android:textColorLink">@color/light_active_color</item>
         <item name="colorPrimaryDark">@android:color/black</item>
+        <item name="android:colorAccent">@color/google_blue_500</item>
         <item name="android:statusBarColor" tools:targetApi="21">@android:color/black</item>
 
         <!--  Overriding AppCompat values -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 965d1ec8..d415947 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -2214,8 +2214,8 @@
     public void onExitVr() {}
 
     /**
-     * Whether this Activity supports moving a {@link Tab} to the
-     * {@link FullscreenWebContentsActivity} when it enters fullscreen.
+     * Whether this Activity supports moving a {@link Tab} to the {@link FullscreenActivity} when it
+     * enters fullscreen.
      */
     public boolean supportsFullscreenActivity() {
         return false;
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 c8238aea..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/FullscreenWebContentsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
similarity index 91%
rename from chrome/android/java/src/org/chromium/chrome/browser/FullscreenWebContentsActivity.java
rename to chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
index f764672..385a35e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/FullscreenWebContentsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
@@ -25,8 +25,11 @@
 
 /**
  * An Activity used to display fullscreen WebContents.
+ *
+ * This Activity used to be called FullscreenWebContentsActivity and extended FullScreenActivity.
+ * When FullScreenActivity was renamed to SingleTabActivity, this was changed to FullscreenActivity.
  */
-public class FullscreenWebContentsActivity extends SingleTabActivity {
+public class FullscreenActivity extends SingleTabActivity {
     private static final String TAG = "FullWebConActivity";
 
     private WebContentsObserver mWebContentsObserver;
@@ -120,12 +123,12 @@
         Activity activity = tab.getActivity();
 
         if (enableFullscreen) {
-            // Send to the FullscreenWebContentsActivity.
-            intent.setClass(tab.getActivity(), FullscreenWebContentsActivity.class);
+            // Send to the FullscreenActivity.
+            intent.setClass(tab.getActivity(), FullscreenActivity.class);
 
             intent.putExtra(IntentHandler.EXTRA_PARENT_COMPONENT, activity.getComponentName());
             // In multiwindow mode we want both activities to be able to launch independent
-            // FullscreenWebContentsActivity's.
+            // FullscreenActivity's.
             intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
         } else {
             // Send back to the Activity it came from.
@@ -140,9 +143,8 @@
             }
 
             ChromeActivity tabActivity = tab.getActivity();
-            if (tabActivity instanceof FullscreenWebContentsActivity) {
-                FullscreenWebContentsActivity fullscreenActivity =
-                        (FullscreenWebContentsActivity) tabActivity;
+            if (tabActivity instanceof FullscreenActivity) {
+                FullscreenActivity fullscreenActivity = (FullscreenActivity) tabActivity;
                 if (fullscreenActivity.mWebContentsObserver != null) {
                     fullscreenActivity.mWebContentsObserver.destroy();
                     fullscreenActivity.mWebContentsObserver = null;
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..47b25c28 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/gsa/ContextReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/gsa/ContextReporter.java
index 9585d550..77b53354 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gsa/ContextReporter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gsa/ContextReporter.java
@@ -51,8 +51,9 @@
     public static final int STATUS_RESULT_IS_NULL = 17;
     public static final int STATUS_RESULT_FAILED = 18;
     public static final int STATUS_SUCCESS_WITH_SELECTION = 19;
+    public static final int STATUS_DUP_ENTRY = 20;
     // This should always stay last and have the highest number.
-    private static final int STATUS_BOUNDARY = 20;
+    private static final int STATUS_BOUNDARY = 21;
 
     private final ChromeActivity mActivity;
     private final GSAContextReportDelegate mDelegate;
@@ -60,6 +61,8 @@
     private TabModelSelectorTabModelObserver mModelObserver;
     private ContextualSearchObserver mContextualSearchObserver;
     private boolean mLastContextWasTitleChange;
+    private String mLastUrl;
+    private String mLastTitle;
     private final AtomicBoolean mContextInUse;
 
     /**
@@ -191,11 +194,20 @@
             Log.d(TAG, "Not reporting, repeated title update");
             return;
         }
+        if (TextUtils.equals(currentTab.getUrl(), mLastUrl)
+                && TextUtils.equals(currentTab.getTitle(), mLastTitle)
+                && displaySelection == null) {
+            reportStatus(STATUS_DUP_ENTRY);
+            Log.d(TAG, "Not reporting, repeated url and title");
+            return;
+        }
 
         reportUsageEndedIfNecessary();
 
         mDelegate.reportContext(currentTab.getUrl(), currentTab.getTitle(), displaySelection);
         mLastContextWasTitleChange = isTitleChange;
+        mLastUrl = currentTab.getUrl();
+        mLastTitle = currentTab.getTitle();
         mContextInUse.set(true);
     }
 
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/IncognitoNewTabPageViewMD.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
index 3616f8d7..e5782bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
@@ -47,8 +47,6 @@
     private TextView mLearnMore;
     private TextView[] mParagraphs;
 
-    boolean mFirstLayout = true;
-
     private static final int BULLETPOINTS_HORIZONTAL_SPACING_DP = 40;
     private static final int CONTENT_WIDTH_DP = 600;
     private static final int WIDE_LAYOUT_THRESHOLD_DP = 720;
@@ -136,7 +134,6 @@
             adjustIcon();
             adjustLayout();
             adjustLearnMore();
-            mFirstLayout = false;
         }
     }
 
@@ -222,6 +219,12 @@
                     new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                             LinearLayout.LayoutParams.WRAP_CONTENT));
             mSubtitle.setMaxWidth(dpToPx(CONTENT_WIDTH_DP));
+
+            // The bulletpoints container takes the same width as subtitle. Since the width can
+            // not be directly measured at this stage, we must calculate it manually.
+            mBulletpointsContainer.setLayoutParams(new LinearLayout.LayoutParams(
+                    dpToPx(Math.min(CONTENT_WIDTH_DP, mWidthDp - 2 * paddingHorizontalDp)),
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
         } else {
             // Large padding.
             paddingHorizontalDp = 0; // Should not be necessary on a screen this large.
@@ -231,20 +234,19 @@
             mContainer.setGravity(Gravity.CENTER_HORIZONTAL);
 
             // Decide the bulletpoints orientation.
-            // TODO(msramek): The total bulletpoints width is consistently miscalculated by 10dp
-            // on the first layout run. Investigate why.
             int totalBulletpointsWidthDp = pxToDp(mBulletpointsContainer.getChildAt(0).getWidth())
                     + pxToDp(mBulletpointsContainer.getChildAt(1).getWidth())
-                    + BULLETPOINTS_HORIZONTAL_SPACING_DP + (mFirstLayout ? 10 : 0);
+                    + BULLETPOINTS_HORIZONTAL_SPACING_DP;
             bulletpointsArrangedHorizontally = totalBulletpointsWidthDp <= CONTENT_WIDTH_DP;
 
             // The subtitle width is equal to the two sets of bulletpoints if they are arranged
             // horizontally. If not, use the default CONTENT_WIDTH_DP.
-            int subtitleWidthPx = bulletpointsArrangedHorizontally
-                    ? dpToPx(totalBulletpointsWidthDp)
-                    : dpToPx(CONTENT_WIDTH_DP);
+            int contentWidthPx = bulletpointsArrangedHorizontally ? dpToPx(totalBulletpointsWidthDp)
+                                                                  : dpToPx(CONTENT_WIDTH_DP);
             mSubtitle.setLayoutParams(new LinearLayout.LayoutParams(
-                    subtitleWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT));
+                    contentWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT));
+            mBulletpointsContainer.setLayoutParams(new LinearLayout.LayoutParams(
+                    contentWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT));
         }
 
         // Apply the bulletpoints orientation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index e4e552fa..d8a8a27e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -25,7 +25,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 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.NativePage;
 import org.chromium.chrome.browser.NativePageHost;
@@ -162,10 +161,6 @@
                 && (url.startsWith(UrlConstants.NTP_URL) || url.startsWith("chrome://newtab"));
     }
 
-    private boolean isNtpOfflinePagesEnabled() {
-        return ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME);
-    }
-
     private class NewTabPageManagerImpl
             extends SuggestionsUiDelegateImpl implements NewTabPageManager {
         public NewTabPageManagerImpl(SuggestionsSource suggestionsSource,
@@ -234,6 +229,22 @@
             if (mFakeboxDelegate == null) return false;
             return mFakeboxDelegate.isCurrentPage(NewTabPage.this);
         }
+
+        @Override
+        public void onLoadingComplete() {
+            if (mIsDestroyed) return;
+
+            long loadTimeMs = (System.nanoTime() - mConstructedTimeNs) / 1000000;
+            RecordHistogram.recordTimesHistogram(
+                    "Tab.NewTabOnload", loadTimeMs, TimeUnit.MILLISECONDS);
+            mIsLoaded = true;
+            StartupMetrics.getInstance().recordOpenedNTP();
+            NewTabPageUma.recordNTPImpression(NewTabPageUma.NTP_IMPRESSION_REGULAR);
+            // If not visible when loading completes, wait until onShown is received.
+            if (!mTab.isHidden()) recordNTPShown();
+
+            SyncSessionsMetrics.recordYoungestForeignTabAgeOnNTP();
+        }
     }
 
     /**
@@ -249,30 +260,11 @@
         }
 
         @Override
-        public void onLoadingComplete(Tile[] items) {
+        public void onLoadingComplete(Tile[] tiles) {
             if (mIsDestroyed) return;
 
-            super.onLoadingComplete(items);
-
-            long loadTimeMs = (System.nanoTime() - mConstructedTimeNs) / 1000000;
-            RecordHistogram.recordTimesHistogram(
-                    "Tab.NewTabOnload", loadTimeMs, TimeUnit.MILLISECONDS);
-            mIsLoaded = true;
-            StartupMetrics.getInstance().recordOpenedNTP();
-            NewTabPageUma.recordNTPImpression(NewTabPageUma.NTP_IMPRESSION_REGULAR);
-            // If not visible when loading completes, wait until onShown is received.
-            if (!mTab.isHidden()) recordNTPShown();
-
-            if (isNtpOfflinePagesEnabled()) {
-                final int maxNumTiles = 12;
-                for (int i = 0; i < items.length; i++) {
-                    if (items[i].isOfflineAvailable()) {
-                        RecordHistogram.recordEnumeratedHistogram(
-                                "NewTabPage.TileOfflineAvailable", i, maxNumTiles);
-                    }
-                }
-            }
-            SyncSessionsMetrics.recordYoungestForeignTabAgeOnNTP();
+            super.onLoadingComplete(tiles);
+            mNewTabPageView.onTilesLoaded();
         }
 
         @Override
@@ -327,7 +319,7 @@
                 // Showing the NTP is only meaningful when the page has been loaded already.
                 if (mIsLoaded) recordNTPShown();
 
-                mNewTabPageView.getTileGroup().onSwitchToForeground();
+                mNewTabPageView.getTileGroup().onSwitchToForeground(/* trackLoadTask = */ false);
             }
 
             @Override
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..d37eebb 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
@@ -108,24 +108,28 @@
     private ChromeActivity mActivity;
     private NewTabPageManager mManager;
     private LogoDelegateImpl mLogoDelegate;
-    private TileGroup.Delegate mTileGroupDelegate;
     private TileGroup mTileGroup;
     private UiConfig mUiConfig;
     private Runnable mSnapScrollRunnable;
     private Runnable mUpdateSearchBoxOnScrollRunnable;
-    private boolean mFirstShow = true;
+
+    /**
+     * Whether the tiles shown in the layout have finished loading.
+     * With {@link #mHasShownView}, it's one of the 2 flags used to track initialisation progress.
+     */
+    private boolean mTilesLoaded;
+
+    /**
+     * Whether the view has been shown at least once.
+     * With {@link #mTilesLoaded}, it's one of the 2 flags used to track initialisation progress.
+     */
+    private boolean mHasShownView;
+
     private boolean mSearchProviderHasLogo = true;
     private boolean mPendingSnapScroll;
     private boolean mInitialized;
     private int mLastScrollY = -1;
 
-    /**
-     * The number of asynchronous tasks that need to complete before the page is done loading.
-     * This starts at one to track when the view is finished attaching to the window.
-     */
-    private int mPendingLoadTasks = 1;
-    private boolean mLoadHasCompleted;
-
     private float mUrlFocusChangePercent;
     private boolean mDisableUrlFocusChangeAnimations;
     private boolean mIsMovingNewTabPageView;
@@ -161,6 +165,12 @@
          * displayed to the user.
          */
         boolean isCurrentPage();
+
+        /**
+         * Called when the NTP has completely finished loading (all views will be inflated
+         * and any dependent resources will have been loaded).
+         */
+        void onLoadingComplete();
     }
 
     /**
@@ -185,7 +195,6 @@
         TraceEvent.begin(TAG + ".initialize()");
         mActivity = tab.getActivity();
         mManager = manager;
-        mTileGroupDelegate = tileGroupDelegate;
         mUiConfig = new UiConfig(this);
 
         assert manager.getSuggestionsSource() != null;
@@ -252,7 +261,7 @@
         mTileGridLayout = (TileGridLayout) mNewTabPageLayout.findViewById(R.id.tile_grid_layout);
         mTileGridLayout.setMaxRows(getMaxTileRows(searchProviderHasLogo));
         mTileGridLayout.setMaxColumns(getMaxTileColumns());
-        mTileGroup = new TileGroup(mActivity, mManager, mContextMenuManager, mTileGroupDelegate,
+        mTileGroup = new TileGroup(mActivity, mManager, mContextMenuManager, tileGroupDelegate,
                 /* observer = */ this, offlinePageBridge, getTileTitleLines());
 
         mSearchProviderLogoView =
@@ -280,11 +289,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();
@@ -540,22 +551,30 @@
     }
 
     /**
-     * Decrements the count of pending load tasks and notifies the manager when the page load
-     * is complete.
+     * Should be called every time of the flags used to track initialisation progress changes.
+     * Finalises initialisation once all the preliminary steps are complete.
+     *
+     * @see #mHasShownView
+     * @see #mTilesLoaded
      */
-    private void loadTaskCompleted() {
-        assert mPendingLoadTasks > 0;
-        mPendingLoadTasks--;
-        if (mPendingLoadTasks == 0) {
-            if (mLoadHasCompleted) {
-                assert false;
-            } else {
-                mLoadHasCompleted = true;
-                mTileGroupDelegate.onLoadingComplete(mTileGroup.getTiles());
-                // Load the logo after everything else is finished, since it's lower priority.
-                loadSearchProviderLogo();
-            }
-        }
+    private void onInitialisationProgressChanged() {
+        if (!hasLoadCompleted()) return;
+
+        mManager.onLoadingComplete();
+
+        // Load the logo after everything else is finished, since it's lower priority.
+        loadSearchProviderLogo();
+    }
+
+    /**
+     * To be called to notify that the tiles have finished loading. Will do nothing if a load was
+     * previously completed.
+     */
+    public void onTilesLoaded() {
+        if (mTilesLoaded) return;
+        mTilesLoaded = true;
+
+        onInitialisationProgressChanged();
     }
 
     /**
@@ -743,9 +762,9 @@
         super.onAttachedToWindow();
         assert mManager != null;
 
-        if (mFirstShow) {
-            loadTaskCompleted();
-            mFirstShow = false;
+        if (!mHasShownView) {
+            mHasShownView = true;
+            onInitialisationProgressChanged();
             NewTabPageUma.recordSearchAvailableLoadTime(mActivity);
             TraceEvent.instant("NewTabPageSearchAvailable)");
         } else {
@@ -900,12 +919,15 @@
         return mRecyclerView.getScrollPosition();
     }
 
+    private boolean hasLoadCompleted() {
+        return mHasShownView && mTilesLoaded;
+    }
+
     // TileGroup.Observer interface.
 
     @Override
     public void onTileDataChanged() {
-        mTileGroup.renderTileViews(
-                mTileGridLayout, !mLoadHasCompleted, shouldUseCondensedTileLayout());
+        mTileGroup.renderTileViews(mTileGridLayout, shouldUseCondensedTileLayout());
         mSnapshotTileGridChanged = true;
 
         // The page contents are initially hidden; otherwise they'll be drawn centered on the page
@@ -936,16 +958,6 @@
         mSnapshotTileGridChanged = true;
     }
 
-    @Override
-    public void onLoadTaskAdded() {
-        mPendingLoadTasks++;
-    }
-
-    @Override
-    public void onLoadTaskCompleted() {
-        loadTaskCompleted();
-    }
-
     private class SnapScrollRunnable implements Runnable {
         @Override
         public void run() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
index 7b2afd6..fb977ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -80,9 +80,7 @@
                     // TODO(jkrcal): Implement in the backend instead. See https://crbug.com/728570
                     uiDelegate.getSuggestionsSource().fetchRemoteSuggestions();
                 } else {
-                    uiDelegate.getSuggestionsSource().fetchSuggestions(mCategoryInfo.getCategory(),
-                            mParentSection.getDisplayedSuggestionIds());
-                    mParentSection.onFetchStarted();
+                    mParentSection.fetchSuggestions();
                 }
                 return;
             case ContentSuggestionsAdditionalAction.NONE:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ChildNode.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ChildNode.java
index 83c4d21..7372e34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ChildNode.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ChildNode.java
@@ -32,6 +32,11 @@
         mParent = null;
     }
 
+    /** @return Whether the node is attached to a parent node. */
+    protected boolean isAttached() {
+        return mParent != null;
+    }
+
     @Override
     public final int getItemCount() {
         assert mNumItems == getItemCountForDebugging();
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..88530ed 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
@@ -189,7 +189,9 @@
             mSections.refreshSuggestions();
         }
 
-        if (mTileGrid != null) mTileGrid.getTileGroup().onSwitchToForeground();
+        if (mTileGrid != null) {
+            mTileGrid.getTileGroup().onSwitchToForeground(/* trackLoadTasks = */ true);
+        }
     }
 
     public int getAboveTheFoldPosition() {
@@ -256,7 +258,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/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
index a0a9e3e0..cf3437a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -128,18 +128,7 @@
 
         SuggestionsSection section = mSections.get(category);
         section.setStatus(status);
-        section.updateSuggestions(mUiDelegate.getSuggestionsSource());
-    }
-
-    @Override
-    public void onMoreSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions) {
-        @CategoryStatus
-        int status = mUiDelegate.getSuggestionsSource().getCategoryStatus(category);
-        if (!canProcessSuggestions(category, status)) return;
-
-        SuggestionsSection section = mSections.get(category);
-        section.setStatus(status);
-        section.appendSuggestions(suggestions, /* userRequested = */ true);
+        section.updateSuggestions();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index f4502db..97a9a0c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -40,6 +40,7 @@
     private final Delegate mDelegate;
     private final SuggestionsCategoryInfo mCategoryInfo;
     private final OfflineModelObserver mOfflineModelObserver;
+    private final SuggestionsSource mSuggestionsSource;
 
     // Children
     private final SectionHeader mHeader;
@@ -87,9 +88,10 @@
             SuggestionsCategoryInfo info) {
         mDelegate = delegate;
         mCategoryInfo = info;
+        mSuggestionsSource = uiDelegate.getSuggestionsSource();
 
         mHeader = new SectionHeader(info.getTitle());
-        mSuggestionsList = new SuggestionsList(uiDelegate, ranker, info);
+        mSuggestionsList = new SuggestionsList(mSuggestionsSource, ranker, info);
         mStatus = StatusItem.createNoSuggestionsItem(info);
         mMoreButton = new ActionItem(this, ranker);
         mProgressIndicator = new ProgressItem();
@@ -104,14 +106,13 @@
     private static class SuggestionsList extends ChildNode implements Iterable<SnippetArticle> {
         private final List<SnippetArticle> mSuggestions = new ArrayList<>();
 
-        // TODO(crbug.com/677672): Replace by SuggestionSource when it handles destruction.
-        private final SuggestionsUiDelegate mUiDelegate;
+        private final SuggestionsSource mSuggestionsSource;
         private final SuggestionsRanker mSuggestionsRanker;
         private final SuggestionsCategoryInfo mCategoryInfo;
 
-        public SuggestionsList(SuggestionsUiDelegate uiDelegate, SuggestionsRanker ranker,
+        public SuggestionsList(SuggestionsSource suggestionsSource, SuggestionsRanker ranker,
                 SuggestionsCategoryInfo categoryInfo) {
-            mUiDelegate = uiDelegate;
+            mSuggestionsSource = suggestionsSource;
             mSuggestionsRanker = ranker;
             mCategoryInfo = categoryInfo;
         }
@@ -194,8 +195,7 @@
         @Override
         public void dismissItem(int position, Callback<String> itemRemovedCallback) {
             checkIndex(position);
-            SuggestionsSource suggestionsSource = mUiDelegate.getSuggestionsSource();
-            if (suggestionsSource == null) {
+            if (!isAttached()) {
                 // It is possible for this method to be called after the NewTabPage has had
                 // destroy() called. This can happen when
                 // NewTabPageRecyclerView.dismissWithAnimation() is called and the animation ends
@@ -205,7 +205,7 @@
             }
 
             SnippetArticle suggestion = remove(position);
-            suggestionsSource.dismissSuggestion(suggestion);
+            mSuggestionsSource.dismissSuggestion(suggestion);
             itemRemovedCallback.onResult(suggestion.mTitle);
         }
 
@@ -355,10 +355,8 @@
      * effect if changing the list of suggestions is not allowed (e.g. because the user has already
      * seen the suggestions). In that case, the section will be flagged as stale.
      * (see {@link #isDataStale()})
-     *
-     * @param suggestionsSource The source used to fetch the new suggestions.
      */
-    public void updateSuggestions(SuggestionsSource suggestionsSource) {
+    public void updateSuggestions() {
         if (mDelegate.isResetAllowed()) clearData();
         if (!canUpdateSuggestions()) {
             mIsDataStale = true;
@@ -368,7 +366,7 @@
         }
 
         List<SnippetArticle> suggestions =
-                suggestionsSource.getSuggestionsForCategory(getCategory());
+                mSuggestionsSource.getSuggestionsForCategory(getCategory());
         Log.d(TAG, "Received %d new suggestions for category %d, had %d previously.",
                 suggestions.size(), getCategory(), mSuggestionsList.getItemCount());
 
@@ -455,8 +453,19 @@
         return true;
     }
 
-    /** Lets the {@link SuggestionsSection} know when a suggestion fetch has been started. */
-    public void onFetchStarted() {
+    /** Fetches additional suggestions only for this section. */
+    public void fetchSuggestions() {
+        mSuggestionsSource.fetchSuggestions(mCategoryInfo.getCategory(),
+                getDisplayedSuggestionIds(), new Callback<List<SnippetArticle>>() {
+                    @Override
+                    public void onResult(List<SnippetArticle> additionalSuggestions) {
+                        if (!isAttached()) return; // The section has been dismissed.
+
+                        mProgressIndicator.setVisible(false);
+                        appendSuggestions(additionalSuggestions, /* userRequested = */ true);
+                    }
+                });
+
         mProgressIndicator.setVisible(true);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index 7ea63ca72..ee4f3ef4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -180,8 +180,9 @@
     }
 
     @Override
-    public void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds) {
-        nativeFetch(mNativeSnippetsBridge, category, displayedSuggestionIds);
+    public void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds,
+            Callback<List<SnippetArticle>> callback) {
+        nativeFetch(mNativeSnippetsBridge, category, displayedSuggestionIds, callback);
     }
 
     @CalledByNative
@@ -232,11 +233,6 @@
     }
 
     @CalledByNative
-    private void onMoreSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions) {
-        if (mObserver != null) mObserver.onMoreSuggestions(category, suggestions);
-    }
-
-    @CalledByNative
     private void onCategoryStatusChanged(@CategoryInt int category, @CategoryStatus int newStatus) {
         if (mObserver != null) mObserver.onCategoryStatusChanged(category, newStatus);
     }
@@ -273,8 +269,8 @@
     private native void nativeFetchSuggestionFavicon(long nativeNTPSnippetsBridge, int category,
             String idWithinCategory, int minimumSizePx, int desiredSizePx,
             Callback<Bitmap> callback);
-    private native void nativeFetch(
-            long nativeNTPSnippetsBridge, int category, String[] knownSuggestions);
+    private native void nativeFetch(long nativeNTPSnippetsBridge, int category,
+            String[] knownSuggestions, Callback<List<SnippetArticle>> callback);
     private native void nativeFetchContextualSuggestions(
             long nativeNTPSnippetsBridge, String url, Callback<List<SnippetArticle>> callback);
     private native void nativeDismissSuggestion(long nativeNTPSnippetsBridge, String url,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
index e71bd86..b20d676 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -23,9 +23,6 @@
         /** Called when a category has a new list of content suggestions. */
         void onNewSuggestions(@CategoryInt int category);
 
-        /** Called when a request for additional suggestions completed. */
-        void onMoreSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions);
-
         /** Called when a category changed its status. */
         void onCategoryStatusChanged(@CategoryInt int category, @CategoryStatus int newStatus);
 
@@ -93,8 +90,10 @@
      * Fetches new suggestions.
      * @param category the category to fetch new suggestions for.
      * @param displayedSuggestionIds ids of suggestions already known and that we want to keep.
+     * @param callback The callback to run with the received suggestions.
      */
-    void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds);
+    void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds,
+            Callback<List<SnippetArticle>> callback);
 
     /**
      * Fetches suggestions related to the provided URL.
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..6a0cd34b 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/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index c65ad816..9833a25 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -43,9 +43,6 @@
     private static final String CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER =
             "contextual_search_current_week_number";
     private static final String HERB_FLAVOR_KEY = "herb_flavor";
-    private static final String WEBAPK_COMMAND_LINE_KEY = "webapk.command_line_enabled";
-    private static final String WEBAPK_RUNTIME_KEY = "webapk.runtime_enabled";
-    private static final String WEBAPK_ANY_PACKAGE_KEY = "webapk.any_package_name";
     private static final String CHROME_HOME_ENABLED_KEY = "chrome_home_enabled";
 
     private static final String CHROME_DEFAULT_BROWSER = "applink.chrome_default_browser";
@@ -346,16 +343,6 @@
         writeString(HERB_FLAVOR_KEY, flavor);
     }
 
-    /** Checks the cached value for the webapk feature. */
-    public boolean getCachedWebApkRuntimeEnabled() {
-        return mSharedPreferences.getBoolean(WEBAPK_RUNTIME_KEY, false);
-    }
-
-    /** Writes the cached value for the webapk feature is enabled. */
-    public void setCachedWebApkRuntimeEnabled(boolean isEnabled) {
-        writeBoolean(WEBAPK_RUNTIME_KEY, isEnabled);
-    }
-
     public boolean getCachedChromeDefaultBrowser() {
         return mSharedPreferences.getBoolean(CHROME_DEFAULT_BROWSER, false);
     }
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/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
index 90572dd..45a19fb4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
@@ -17,6 +17,12 @@
 @JNIAdditionalImport(MostVisitedSites.class) // Needed for the Observer usage in the native calls.
 public class MostVisitedSitesBridge
         implements MostVisitedSites, HomepageManager.HomepageStateListener {
+    /**
+     * Maximum number of tiles that is explicitly supported. UMA relies on this value, so even if
+     * the UI supports it, getting more can raise unexpected issues.
+     */
+    public static final int MAX_TILE_COUNT = 12;
+
     private long mNativeMostVisitedSitesBridge;
 
     /**
@@ -63,6 +69,8 @@
 
     @Override
     public void setObserver(final Observer observer, int numSites) {
+        assert numSites <= MAX_TILE_COUNT;
+
         Observer wrappedObserver = new Observer() {
             @Override
             public void onMostVisitedURLsAvailable(
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/SuggestionsMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
index e6a76278..4dba17ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
@@ -113,6 +113,15 @@
     }
 
     /**
+     * Records which tiles are available offline once the site suggestions finished loading.
+     * @param tileIndex index of a tile whose URL is available offline.
+     */
+    public static void recordTileOfflineAvailability(int tileIndex) {
+        RecordHistogram.recordEnumeratedHistogram("NewTabPage.TileOfflineAvailable", tileIndex,
+                MostVisitedSitesBridge.MAX_TILE_COUNT);
+    }
+
+    /**
      * Measures the amount of time it takes for date formatting in order to track StrictMode
      * violations.
      * See https://crbug.com/639877
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/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
index 0ba23035..87cd6b2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -85,12 +85,6 @@
         if (isVisible()) notifyItemChanged(0, new ViewHolder.UpdateOfflineBadgeCallback(tile));
     }
 
-    @Override
-    public void onLoadTaskAdded() {}
-
-    @Override
-    public void onLoadTaskCompleted() {}
-
     public TileGroup getTileGroup() {
         return mTileGroup;
     }
@@ -122,8 +116,7 @@
         }
 
         public void updateTiles(TileGroup tileGroup) {
-            tileGroup.renderTileViews(mLayout, /* trackLoadTasks = */ false,
-                    /* condensed = */ false);
+            tileGroup.renderTileViews(mLayout, /* condensed = */ false);
         }
 
         public void updateIconView(Tile tile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
index 2842181..40c0b40 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -11,6 +11,7 @@
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.AsyncTask;
+import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
@@ -37,6 +38,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -68,7 +70,7 @@
         void setMostVisitedSitesObserver(MostVisitedSites.Observer observer, int maxResults);
 
         /**
-         * Called when the NTP has completely finished loading (all views will be inflated
+         * Called when the tile group has completely finished loading (all views will be inflated
          * and any dependent resources will have been loaded).
          * @param tiles The tiles owned by the {@link TileGroup}. Used to record metrics.
          */
@@ -107,16 +109,34 @@
          * @param tile The tile for which the visibility of the offline badge has changed.
          */
         void onTileOfflineBadgeVisibilityChanged(Tile tile);
+    }
+
+    /**
+     * Constants used to track the current operations on the group and notify the {@link Delegate}
+     * when the expected sequence of potentially asynchronous operations is complete.
+     */
+    @VisibleForTesting
+    @IntDef({TileTask.FETCH_DATA, TileTask.SCHEDULE_ICON_FETCH, TileTask.FETCH_ICON})
+    @interface TileTask {
+        /**
+         * An event that should result in new data being loaded happened.
+         * Can be an asynchronous task, spanning from when the {@link Observer} is registered to
+         * when the initial load completes.
+         */
+        int FETCH_DATA = 1;
 
         /**
-         * Called when an asynchronous loading task has started.
+         * New tile data has been loaded and we are expecting the related icons to be fetched.
+         * Can be an asynchronous task, as we rely on it being triggered by the embedder, some time
+         * after {@link Observer#onTileDataChanged()} is called.
          */
-        void onLoadTaskAdded();
+        int SCHEDULE_ICON_FETCH = 2;
 
         /**
-         * Called when an asynchronous loading task has completed.
+         * The icon for a tile is being fetched.
+         * Asynchronous task, that is started for each icon that needs to be loaded.
          */
-        void onLoadTaskCompleted();
+        int FETCH_ICON = 3;
     }
 
     private static final String TAG = "TileGroup";
@@ -130,6 +150,15 @@
     private final ContextMenuManager mContextMenuManager;
     private final Delegate mTileGroupDelegate;
     private final Observer mObserver;
+
+    /**
+     * Tracks the tasks currently in flight.
+     *
+     * We only care about which ones are pending, not their order, and we can have multiple tasks
+     * pending of the same type. Hence exposing the type as Collection rather than List or Set.
+     */
+    private final Collection<Integer> mPendingTasks = new ArrayList<>();
+
     private final int mTitleLinesCount;
     private final int mMinIconSize;
     private final int mDesiredIconSize;
@@ -259,7 +288,7 @@
      * @param maxResults The maximum number of sites to retrieve.
      */
     public void startObserving(int maxResults) {
-        mObserver.onLoadTaskAdded();
+        addTask(TileTask.FETCH_DATA);
         mTileGroupDelegate.setMostVisitedSitesObserver(this, maxResults);
     }
 
@@ -267,10 +296,9 @@
      * Renders tile views in the given {@link TileGridLayout}, reusing existing tile views where
      * possible because view inflation and icon loading are slow.
      * @param parent The layout to render the tile views into.
-     * @param trackLoadTasks Whether to track load tasks.
      * @param condensed Whether to use a condensed layout.
      */
-    public void renderTileViews(ViewGroup parent, boolean trackLoadTasks, boolean condensed) {
+    public void renderTileViews(ViewGroup parent, boolean condensed) {
         // Map the old tile views by url so they can be reused later.
         Map<String, TileView> oldTileViews = new HashMap<>();
         int childCount = parent.getChildCount();
@@ -286,13 +314,16 @@
         for (Tile tile : mTiles) {
             TileView tileView = oldTileViews.get(tile.getUrl());
             if (tileView == null) {
-                tileView = buildTileView(tile, parent, trackLoadTasks, condensed);
+                tileView = buildTileView(tile, parent, condensed);
             } else {
                 tileView.updateIfDataChanged(tile);
             }
 
             parent.addView(tileView);
         }
+
+        // Icon fetch scheduling was done when building the tile views.
+        if (isLoadTracked()) removeTask(TileTask.SCHEDULE_ICON_FETCH);
     }
 
     public Tile[] getTiles() {
@@ -303,30 +334,35 @@
         return mHasReceivedData;
     }
 
-    /** To be called when the view displaying the tile group becomes visible. */
-    public void onSwitchToForeground() {
+    /**
+     * To be called when the view displaying the tile group becomes visible.
+     * @param trackLoadTask whether the delegate should be notified that the load is completed
+     *                      through {@link Delegate#onLoadingComplete(Tile[])}.
+     */
+    public void onSwitchToForeground(boolean trackLoadTask) {
+        if (trackLoadTask) addTask(TileTask.FETCH_DATA);
         if (mPendingTiles != null) loadTiles();
+        if (trackLoadTask) removeTask(TileTask.FETCH_DATA);
     }
 
     /**
      * Inflates a new tile view, initializes it, and loads an icon for it.
      * @param tile The tile that holds the data to populate the new tile view.
      * @param parentView The parent of the new tile view.
-     * @param trackLoadTask Whether to track a load task.
      * @param condensed Whether to use a condensed layout.
      * @return The new tile view.
      */
     @VisibleForTesting
-    TileView buildTileView(
-            Tile tile, ViewGroup parentView, boolean trackLoadTask, boolean condensed) {
+    TileView buildTileView(Tile tile, ViewGroup parentView, boolean condensed) {
         TileView tileView = (TileView) LayoutInflater.from(parentView.getContext())
                                     .inflate(R.layout.tile_view, parentView, false);
         tileView.initialize(tile, mTitleLinesCount, condensed);
 
+        if (isLoadTracked()) addTask(TileTask.FETCH_ICON);
+
         // Note: It is important that the callbacks below don't keep a reference to the tile or
         // modify them as there is no guarantee that the same tile would be used to update the view.
-        LargeIconCallback iconCallback = new LargeIconCallbackImpl(tile.getUrl(), trackLoadTask);
-        if (trackLoadTask) mObserver.onLoadTaskAdded();
+        LargeIconCallback iconCallback = new LargeIconCallbackImpl(tile.getUrl(), isLoadTracked());
         loadWhitelistIcon(tile, iconCallback);
 
         TileInteractionDelegate delegate = new TileInteractionDelegate(tile.getUrl());
@@ -389,8 +425,11 @@
         }
 
         if (countChanged) mObserver.onTileCountChanged();
+
+        if (isLoadTracked()) addTask(TileTask.SCHEDULE_ICON_FETCH);
         mObserver.onTileDataChanged();
-        if (isInitialLoad) mObserver.onLoadTaskCompleted();
+
+        if (isInitialLoad) removeTask(TileTask.FETCH_DATA);
     }
 
     /** @return A tile matching the provided URL, or {@code null} if none is found. */
@@ -402,6 +441,32 @@
         return null;
     }
 
+    private void addTask(@TileTask int task) {
+        mPendingTasks.add(task);
+    }
+
+    private void removeTask(@TileTask int task) {
+        boolean removedTask = mPendingTasks.remove(Integer.valueOf(task));
+        assert removedTask;
+
+        if (mPendingTasks.isEmpty()) mTileGroupDelegate.onLoadingComplete(getTiles());
+    }
+
+    /**
+     * @return Whether the current load is being tracked. Unrequested task tracking updates should
+     * not be sent, as it would cause calling {@link Delegate#onLoadingComplete(Tile[])} at the
+     * wrong moment.
+     */
+    private boolean isLoadTracked() {
+        return mPendingTasks.contains(TileTask.FETCH_DATA)
+                || mPendingTasks.contains(TileTask.SCHEDULE_ICON_FETCH);
+    }
+
+    @VisibleForTesting
+    boolean isTaskPending(@TileTask int task) {
+        return mPendingTasks.contains(task);
+    }
+
     private class LargeIconCallbackImpl implements LargeIconCallback {
         private final String mUrl;
         private final boolean mTrackLoadTask;
@@ -440,7 +505,7 @@
             }
 
             // This call needs to be made after the tiles are completely initialised, for UMA.
-            if (mTrackLoadTask) mObserver.onLoadTaskCompleted();
+            if (mTrackLoadTask) removeTask(TileTask.FETCH_ICON);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
index 0f49fc3e..02b7a4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
@@ -13,6 +13,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 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.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -89,7 +90,9 @@
 
     @Override
     public void onLoadingComplete(Tile[] tiles) {
-        assert !mIsDestroyed;
+        // This method is called after network calls complete. It could happen after the suggestions
+        // surface is destroyed.
+        if (mIsDestroyed) return;
 
         for (int i = 0; i < tiles.length; i++) {
             mMostVisitedSites.recordTileImpression(
@@ -97,6 +100,14 @@
         }
 
         mMostVisitedSites.recordPageImpression(tiles.length);
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME)) {
+            for (int i = 0; i < tiles.length; i++) {
+                if (tiles[i].isOfflineAvailable()) {
+                    SuggestionsMetrics.recordTileOfflineAvailability(i);
+                }
+            }
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index fe98ab8..6b0b05e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -28,7 +28,7 @@
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.FullscreenWebContentsActivity;
+import org.chromium.chrome.browser.FullscreenActivity;
 import org.chromium.chrome.browser.RepostFormWarningDialog;
 import org.chromium.chrome.browser.document.DocumentUtils;
 import org.chromium.chrome.browser.document.DocumentWebContentsDelegate;
@@ -221,7 +221,7 @@
     public void toggleFullscreenModeForTab(boolean enableFullscreen) {
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.FULLSCREEN_ACTIVITY)
                 && mTab.getActivity().supportsFullscreenActivity()) {
-            FullscreenWebContentsActivity.toggleFullscreenMode(enableFullscreen, mTab);
+            FullscreenActivity.toggleFullscreenMode(enableFullscreen, mTab);
         } else {
             mTab.toggleFullscreenMode(enableFullscreen);
         }
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..b6fe6ce7 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/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 9c5f64e..3a0ac2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.omnibox.OmniboxPlaceholderFieldTrial;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
-import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
 import org.chromium.components.signin.AccountManagerHelper;
 import org.chromium.ui.base.DeviceFormFactor;
 
@@ -187,7 +186,6 @@
      */
     public static void cacheNativeFlags() {
         cacheHerbFlavor();
-        ChromeWebApkHost.cacheEnabledStateForNextLaunch();
         cacheChromeHomeEnabled();
         FirstRunGlueImpl.cacheFirstRunPrefs();
         OmniboxPlaceholderFieldTrial.cacheOmniboxPlaceholderGroup();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
index 77270c0..81bb2d14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -4,18 +4,7 @@
 
 package org.chromium.chrome.browser.webapps;
 
-import android.os.StrictMode;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.chrome.browser.AppHooks;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.GooglePlayInstallState;
-import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
-import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler;
-import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.webapk.lib.client.WebApkValidator;
 
 /**
@@ -24,90 +13,16 @@
 public class ChromeWebApkHost {
     private static final String TAG = "ChromeWebApkHost";
 
-    /** Whether installing WebAPks from Google Play is possible. */
-    private static Integer sGooglePlayInstallState;
-
-    private static Boolean sInstallsEnabledForTesting;
-
     public static void init() {
         WebApkValidator.init(
                 ChromeWebApkHostSignature.EXPECTED_SIGNATURE, ChromeWebApkHostSignature.PUBLIC_KEY);
     }
 
-    public static void initForTesting(boolean installsEnabled) {
-        sInstallsEnabledForTesting = installsEnabled;
-        sGooglePlayInstallState = installsEnabled ? GooglePlayInstallState.SUPPORTED
-                                                  : GooglePlayInstallState.NO_PLAY_SERVICES;
-    }
-
-    /** Computes the GooglePlayInstallState. */
-    private static int computeGooglePlayInstallState() {
-        if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices(
-                    ContextUtils.getApplicationContext(),
-                    new UserRecoverableErrorHandler.Silent())) {
-            return GooglePlayInstallState.NO_PLAY_SERVICES;
-        }
-
-        GooglePlayWebApkInstallDelegate delegate =
-                AppHooks.get().getGooglePlayWebApkInstallDelegate();
-        if (delegate == null) {
-            return GooglePlayInstallState.DISABLED_OTHER;
-        }
-
-        return GooglePlayInstallState.SUPPORTED;
-    }
-
-    /** Returns whether installing WebAPKs is possible. */
-    @CalledByNative
-    private static boolean canInstallWebApk() {
-        if (sInstallsEnabledForTesting != null) return sInstallsEnabledForTesting;
-
-        return isEnabledInPrefs()
-                && getGooglePlayInstallState() == GooglePlayInstallState.SUPPORTED;
-    }
-
-    @CalledByNative
-    private static int getGooglePlayInstallState() {
-        if (sGooglePlayInstallState == null) {
-            sGooglePlayInstallState = computeGooglePlayInstallState();
-        }
-        return sGooglePlayInstallState;
-    }
-
     /* Returns whether launching renderer in WebAPK process is enabled by Chrome. */
     public static boolean canLaunchRendererInWebApkProcess() {
         return LibraryLoader.isInitialized() && nativeCanLaunchRendererInWebApkProcess();
     }
 
-    /**
-     * Check the cached value to figure out if the feature is enabled. We have to use the cached
-     * value because native library may not yet been loaded.
-     * @return Whether the feature is enabled.
-     */
-    private static boolean isEnabledInPrefs() {
-        // Will go away once the feature is enabled for everyone by default.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            return ChromePreferenceManager.getInstance().getCachedWebApkRuntimeEnabled();
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-    }
-
-    /**
-     * Once native is loaded we can consult the command-line (set via about:flags) and also finch
-     * state to see if we should enable WebAPKs.
-     */
-    public static void cacheEnabledStateForNextLaunch() {
-        ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance();
-
-        boolean wasEnabled = isEnabledInPrefs();
-        boolean isEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.IMPROVED_A2HS);
-        if (isEnabled != wasEnabled) {
-            Log.d(TAG, "WebApk setting changed (%s => %s)", wasEnabled, isEnabled);
-            preferenceManager.setCachedWebApkRuntimeEnabled(isEnabled);
-        }
-    }
 
     private static native boolean nativeCanLaunchRendererInWebApkProcess();
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6d29d30d..690d0d0 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -39,7 +39,7 @@
   "java/src/org/chromium/chrome/browser/DevToolsServer.java",
   "java/src/org/chromium/chrome/browser/FileProviderHelper.java",
   "java/src/org/chromium/chrome/browser/FrozenNativePage.java",
-  "java/src/org/chromium/chrome/browser/FullscreenWebContentsActivity.java",
+  "java/src/org/chromium/chrome/browser/FullscreenActivity.java",
   "java/src/org/chromium/chrome/browser/InsetObserverView.java",
   "java/src/org/chromium/chrome/browser/IntentHandler.java",
   "java/src/org/chromium/chrome/browser/IntentHelper.java",
@@ -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",
@@ -1326,7 +1328,7 @@
   "javatests/src/org/chromium/chrome/browser/CrashTest.java",
   "javatests/src/org/chromium/chrome/browser/ExampleUiCaptureTest.java",
   "javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java",
-  "javatests/src/org/chromium/chrome/browser/FullscreenWebContentsActivityTest.java",
+  "javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java",
@@ -1513,6 +1515,8 @@
   "javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/VoiceSuggestionProviderTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeaderTest.java",
+  "javatests/src/org/chromium/chrome/browser/page_info/ConnectionInfoPopupTest.java",
+  "javatests/src/org/chromium/chrome/browser/page_info/PageInfoPopupTest.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java",
@@ -1794,8 +1798,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/FullscreenWebContentsActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
similarity index 86%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenWebContentsActivityTest.java
rename to chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
index 3ca622f9..76360db 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenWebContentsActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
@@ -32,13 +32,13 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * Tests for FullscreenWebContentsActivity.
+ * Tests for FullscreenActivity.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         MediaSwitches.IGNORE_AUTOPLAY_RESTRICTIONS_FOR_TESTS,
         "enable-features=" + ChromeFeatureList.FULLSCREEN_ACTIVITY})
-public class FullscreenWebContentsActivityTest {
+public class FullscreenActivityTest {
     private static final String TEST_PATH = "/content/test/data/media/video-player.html";
     private static final String VIDEO_ID = "video";
 
@@ -65,18 +65,18 @@
     }
 
     /**
-     * Manually moves a Tab from a ChromeTabbedActivity to a FullscreenWebContentsActivity and back.
+     * Manually moves a Tab from a ChromeTabbedActivity to a FullscreenActivity and back.
      */
     @Test
     @MediumTest
     public void testTransfer() throws Throwable {
         final Tab tab = mActivityTestRule.getActivity().getActivityTab();
 
-        moveTabToActivity(mActivity, tab, FullscreenWebContentsActivity.class);
-        waitForActivity(FullscreenWebContentsActivity.class);
+        moveTabToActivity(mActivity, tab, FullscreenActivity.class);
+        waitForActivity(FullscreenActivity.class);
 
-        final FullscreenWebContentsActivity fullscreenActivity =
-                (FullscreenWebContentsActivity) ApplicationStatus.getLastTrackedFocusedActivity();
+        final FullscreenActivity fullscreenActivity =
+                (FullscreenActivity) ApplicationStatus.getLastTrackedFocusedActivity();
         Assert.assertEquals(tab.getId(), fullscreenActivity.getActivityTab().getId());
 
         moveTabToActivity(fullscreenActivity, tab, ChromeTabbedActivity.class);
@@ -96,7 +96,7 @@
                         IntentHandler.EXTRA_PARENT_COMPONENT, fromActivity.getComponentName());
                 intent.putExtra(Browser.EXTRA_APPLICATION_ID, fromActivity.getPackageName());
 
-                if (targetClass == FullscreenWebContentsActivity.class) {
+                if (targetClass == FullscreenActivity.class) {
                     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 }
 
@@ -124,14 +124,14 @@
     }
 
     /**
-     * Toggles fullscreen to check FullscreenWebContentsActivity has been started.
+     * Toggles fullscreen to check FullscreenActivity has been started.
      */
     @Test
     @MediumTest
     public void testFullscreen() throws Throwable {
         Activity original = mActivity;
 
-        FullscreenWebContentsActivity fullscreenActivity = enterFullscreen();
+        FullscreenActivity fullscreenActivity = enterFullscreen();
         DOMUtils.exitFullscreen(fullscreenActivity.getCurrentContentViewCore().getWebContents());
 
         ChromeTabbedActivity activity = waitForActivity(ChromeTabbedActivity.class);
@@ -148,7 +148,7 @@
     @MediumTest
     public void testExitOnBack() throws Throwable {
         Activity original = mActivity;
-        final FullscreenWebContentsActivity fullscreenActivity = enterFullscreen();
+        final FullscreenActivity fullscreenActivity = enterFullscreen();
         mUiThreadTestRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -164,10 +164,10 @@
     }
 
     /**
-     * Clicks on the fullscreen button in the test page, waits for the FullscreenWebContentsActivity
+     * Clicks on the fullscreen button in the test page, waits for the FullscreenActivity
      * to be started and for it to go fullscreen.
      */
-    private FullscreenWebContentsActivity enterFullscreen() throws Throwable {
+    private FullscreenActivity enterFullscreen() throws Throwable {
         // Start playback to guarantee it's properly loaded.
         WebContents webContents = mActivity.getCurrentContentViewCore().getWebContents();
         Assert.assertTrue(DOMUtils.isMediaPaused(webContents, VIDEO_ID));
@@ -177,8 +177,7 @@
         // Trigger requestFullscreen() via a click on a button.
         Assert.assertTrue(DOMUtils.clickNode(mActivity.getCurrentContentViewCore(), "fullscreen"));
 
-        final FullscreenWebContentsActivity fullscreenActivity =
-                waitForActivity(FullscreenWebContentsActivity.class);
+        final FullscreenActivity fullscreenActivity = waitForActivity(FullscreenActivity.class);
 
         CriteriaHelper.pollInstrumentationThread(new Criteria() {
             @Override
@@ -203,7 +202,7 @@
     public void testFullscreenFlags() throws Throwable {
         int old = mActivity.getTabsView().getSystemUiVisibility();
 
-        FullscreenWebContentsActivity fullscreenActivity = enterFullscreen();
+        FullscreenActivity fullscreenActivity = enterFullscreen();
         DOMUtils.exitFullscreen(fullscreenActivity.getCurrentContentViewCore().getWebContents());
 
         waitForActivity(ChromeTabbedActivity.class);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
index 04900696..4629b92 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
@@ -17,6 +17,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -138,6 +139,7 @@
     @Test
     @SmallTest
     @UiThreadTest
+    @DisabledTest // Timing out on the try bot. http://crbug.com/740786
     @Feature({"Bookmark"})
     public void testGetMoveDestinations() throws Throwable {
         BookmarkId folderA = mBookmarkBridge.addFolder(mMobileNode, 0, "a");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkModelTest.java
index a0f83263..11010dd9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkModelTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkModelTest.java
@@ -17,6 +17,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -132,6 +133,7 @@
     @SmallTest
     @UiThreadTest
     @Feature({"Bookmark"})
+    @DisabledTest // Timing out on the try bot. http://crbug.com/740786
     public void testGetChildIDs() throws Throwable {
         BookmarkId folderA = mBookmarkModel.addFolder(mMobileNode, 0, "fa");
         HashSet<BookmarkId> expectedChildren = new HashSet<>();
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/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index b66562a..3ce2e7a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -472,7 +472,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                ntpView.getTileGroup().onSwitchToForeground(); // Force the tiles to be refreshed.
+                ntpView.getTileGroup().onSwitchToForeground(false); // Force tile refresh.
             }
         });
         CriteriaHelper.pollUiThread(new Criteria("The tile grid was not updated.") {
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/javatests/src/org/chromium/chrome/browser/page_info/ConnectionInfoPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/ConnectionInfoPopupTest.java
new file mode 100644
index 0000000..b0d7df8
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/ConnectionInfoPopupTest.java
@@ -0,0 +1,49 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.page_info;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+/**
+ * Tests for ConnectionInfoPopup.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class ConnectionInfoPopupTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    /**
+     * Tests that ConnectionInfoPopup can be instantiated and shown.
+     */
+    @Test
+    @MediumTest
+    @Feature({"ConnectionInfoPopup"})
+    @RetryOnFailure
+    public void testShow() throws InterruptedException {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                ConnectionInfoPopup.show(mActivityTestRule.getActivity(),
+                        mActivityTestRule.getActivity().getActivityTab().getWebContents());
+            }
+        });
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoPopupTest.java
new file mode 100644
index 0000000..c226e01
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoPopupTest.java
@@ -0,0 +1,50 @@
+// 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.page_info;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+/**
+ * Tests for PageInfoPopup.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class PageInfoPopupTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    /**
+     * Tests that PageInfoPopup can be instantiated and shown.
+     */
+    @Test
+    @MediumTest
+    @Feature({"PageInfoPopup"})
+    @RetryOnFailure
+    public void testShow() throws InterruptedException {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                PageInfoPopup.show(mActivityTestRule.getActivity(),
+                        mActivityTestRule.getActivity().getActivityTab(), null,
+                        PageInfoPopup.OPENED_FROM_MENU);
+            }
+        });
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
index 6461881..761d41d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
@@ -177,7 +177,6 @@
     @Before
     public void setUp() throws Exception {
         mActivityTestRule.startMainActivityOnBlankPage();
-        ChromeWebApkHost.initForTesting(false);
         mTestServer = EmbeddedTestServer.createAndStartServer(
                 InstrumentationRegistry.getInstrumentation().getContext());
         mShortcutHelperDelegate = new TestShortcutHelperDelegate();
@@ -271,6 +270,9 @@
     @Test
     @SmallTest
     @Feature("{Webapp}")
+    @CommandLineFlags.Add({ContentSwitches.DISABLE_POPUP_BLOCKING,
+            // TODO(yfriedman): Force WebApks off as this tests old A2HS behaviour.
+            "disable-field-trial-config"})
     public void testAddWebappShortcutSplashScreenIcon() throws Exception {
         try {
             // Sets the overriden factory to observer splash screen update.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
index 9a33be4de..a1f1b87 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
@@ -173,8 +173,9 @@
         List<SnippetArticle> newSuggestions1 = createDummySuggestions(2, CATEGORY1, "new");
         List<SnippetArticle> newSuggestions2 = createDummySuggestions(2, CATEGORY2, "new");
 
-        sectionList.onMoreSuggestions(CATEGORY1, newSuggestions1.subList(0, 1));
-        sectionList.onMoreSuggestions(CATEGORY2, newSuggestions2);
+        sectionList.getSectionForTesting(CATEGORY1).appendSuggestions(
+                newSuggestions1.subList(0, 1), true);
+        sectionList.getSectionForTesting(CATEGORY2).appendSuggestions(newSuggestions2, true);
 
         bindViewHolders(sectionList, 3, sectionList.getItemCount());
 
@@ -207,7 +208,8 @@
         assertThat(newSuggestions2.get(1).getPerSectionRank(), equalTo(5));
 
         // Add one more suggestions1
-        sectionList.onMoreSuggestions(CATEGORY1, newSuggestions1.subList(1, 2));
+        sectionList.getSectionForTesting(CATEGORY1).appendSuggestions(
+                newSuggestions1.subList(1, 2), true);
         bindViewHolders(sectionList);
 
         // After the changes we should have:
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
index 3eecc79..8d73138 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -45,7 +45,6 @@
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder.UpdateLayoutParamsCallback;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
-import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
 import org.chromium.chrome.browser.suggestions.ContentSuggestionsAdditionalAction;
 import org.chromium.chrome.browser.suggestions.SuggestionsEventReporter;
@@ -53,6 +52,7 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.CategoryInfoBuilder;
+import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
 import java.util.ArrayList;
@@ -79,14 +79,25 @@
     private NodeParent mParent;
     @Mock
     private SuggestionsUiDelegate mUiDelegate;
+
+    private FakeSuggestionsSource mSuggestionsSource;
+
     private FakeOfflinePageBridge mBridge;
 
     @Before
     public void setUp() {
         RecordUserAction.setDisabledForTests(true);
         MockitoAnnotations.initMocks(this);
+
         mBridge = new FakeOfflinePageBridge();
 
+        mSuggestionsSource = spy(new FakeSuggestionsSource());
+        mSuggestionsSource.setStatusForCategory(TEST_CATEGORY_ID, CategoryStatus.AVAILABLE);
+        when(mUiDelegate.getSuggestionsSource()).thenReturn(mSuggestionsSource);
+        when(mUiDelegate.getNavigationDelegate())
+                .thenReturn(mock(SuggestionsNavigationDelegate.class));
+        when(mUiDelegate.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class));
+
         // Set empty variation params for the test.
         CardsVariationParameters.setTestVariationParams(new HashMap<String, String>());
     }
@@ -322,8 +333,8 @@
     @Feature({"Ntp"})
     public void testOfflineStatusIgnoredIfDetached() {
         final int suggestionCount = 2;
-        final List<SnippetArticle> suggestions = createDummySuggestions(suggestionCount,
-                TEST_CATEGORY_ID);
+        final List<SnippetArticle> suggestions =
+                mSuggestionsSource.createAndSetSuggestions(suggestionCount, TEST_CATEGORY_ID);
         assertNull(suggestions.get(0).getOfflinePageOfflineId());
         assertNull(suggestions.get(1).getOfflinePageOfflineId());
 
@@ -427,11 +438,12 @@
     @Test
     @Feature({"Ntp"})
     public void testUpdateSectionReplacesSuggestions() {
-        SuggestionsSection section =
-                createSectionWithSuggestions(createDummySuggestions(4, TEST_CATEGORY_ID));
+        SuggestionsSection section = createSectionWithSuggestions(
+                mSuggestionsSource.createAndSetSuggestions(4, TEST_CATEGORY_ID));
         assertEquals(4, section.getSuggestionsCount());
 
-        section.updateSuggestions(createSourceFor(createDummySuggestions(3, TEST_CATEGORY_ID)));
+        mSuggestionsSource.createAndSetSuggestions(3, TEST_CATEGORY_ID);
+        section.updateSuggestions();
         verify(mParent).onItemRangeRemoved(section, 1, 4);
         verify(mParent).onItemRangeInserted(section, 1, 3);
         assertEquals(3, section.getSuggestionsCount());
@@ -450,11 +462,12 @@
         params.put("ignore_updates_for_existing_suggestions", "true");
         CardsVariationParameters.setTestVariationParams(params);
 
-        SuggestionsSection section =
-                createSectionWithSuggestions(createDummySuggestions(4, TEST_CATEGORY_ID));
+        SuggestionsSection section = createSectionWithSuggestions(
+                mSuggestionsSource.createAndSetSuggestions(4, TEST_CATEGORY_ID));
         assertEquals(4, section.getSuggestionsCount());
 
-        section.updateSuggestions(createSourceFor(createDummySuggestions(3, TEST_CATEGORY_ID)));
+        mSuggestionsSource.createAndSetSuggestions(3, TEST_CATEGORY_ID);
+        section.updateSuggestions();
         verify(mParent, never()).onItemRangeRemoved(any(TreeNode.class), anyInt(), anyInt());
         verify(mParent, never()).onItemRangeInserted(any(TreeNode.class), anyInt(), anyInt());
         assertEquals(4, section.getSuggestionsCount());
@@ -468,7 +481,8 @@
     @Test
     @Feature({"Ntp"})
     public void testUpdateSectionDoesNotReplaceFirstSuggestionWhenSeen() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
+        List<SnippetArticle> snippets =
+                mSuggestionsSource.createAndSetSuggestions(4, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
@@ -479,9 +493,8 @@
         bindViewHolders(section, 1, 2);
 
         List<SnippetArticle> newSnippets =
-                createDummySuggestions(3, TEST_CATEGORY_ID, "new");
-        // Copy the list when passing to the section - it may alter it but we later need it.
-        section.updateSuggestions(createSourceFor(new ArrayList<>(newSnippets)));
+                mSuggestionsSource.createAndSetSuggestions(3, TEST_CATEGORY_ID, "new");
+        section.updateSuggestions();
         verify(mParent).onItemRangeRemoved(section, 2, 3);
         verify(mParent).onItemRangeInserted(section, 2, 2);
         assertEquals(3, section.getSuggestionsCount());
@@ -502,7 +515,8 @@
     @Test
     @Feature({"Ntp"})
     public void testUpdateSectionDoesNotReplaceFirstTwoSuggestionWhenSeen() {
-        List<SnippetArticle> snippets = createDummySuggestions(4, TEST_CATEGORY_ID, "old");
+        List<SnippetArticle> snippets =
+                mSuggestionsSource.createAndSetSuggestions(4, TEST_CATEGORY_ID, "old");
         // Copy the list when passing to the section - it may alter it but we later need it.
         SuggestionsSection section =
                 createSectionWithSuggestions(new ArrayList<>(snippets));
@@ -513,9 +527,8 @@
         bindViewHolders(section, 1, 3);
 
         List<SnippetArticle> newSnippets =
-                createDummySuggestions(3, TEST_CATEGORY_ID, "new");
-        // Copy the list when passing to the section - it may alter it but we later need it.
-        section.updateSuggestions(createSourceFor(new ArrayList<>(newSnippets)));
+                mSuggestionsSource.createAndSetSuggestions(3, TEST_CATEGORY_ID, "new");
+        section.updateSuggestions();
         verify(mParent).onItemRangeRemoved(section, 3, 2);
         verify(mParent).onItemRangeInserted(section, 3, 1);
         assertEquals(3, section.getSuggestionsCount());
@@ -545,7 +558,8 @@
         // Indices in section are off-by-one (index 0 is the header).
         bindViewHolders(section, 1, 3);
 
-        section.updateSuggestions(createSourceFor(createDummySuggestions(1, TEST_CATEGORY_ID)));
+        mSuggestionsSource.createAndSetSuggestions(1, TEST_CATEGORY_ID);
+        section.updateSuggestions();
         // Even though the new list has just one suggestion, we need to keep the two seen ones
         // around.
         verify(mParent).onItemRangeRemoved(section, 3, 2);
@@ -583,7 +597,9 @@
 
         assertEquals(1, section.getSuggestionsCount());
 
-        section.updateSuggestions(createSourceFor(createDummySuggestions(4, TEST_CATEGORY_ID)));
+        mSuggestionsSource.setSuggestionsForCategory(
+                TEST_CATEGORY_ID, createDummySuggestions(4, TEST_CATEGORY_ID));
+        section.updateSuggestions();
         // We do not touch the current list if all has been seen.
         verify(mParent, never()).onItemRangeRemoved(any(TreeNode.class), anyInt(), anyInt());
         verify(mParent, never()).onItemRangeInserted(any(TreeNode.class), anyInt(), anyInt());
@@ -606,7 +622,9 @@
         // Bind all the suggestions - indicate that they are being viewed.
         bindViewHolders(section);
 
-        section.updateSuggestions(createSourceFor(createDummySuggestions(3, TEST_CATEGORY_ID)));
+        mSuggestionsSource.setSuggestionsForCategory(
+                TEST_CATEGORY_ID, createDummySuggestions(3, TEST_CATEGORY_ID));
+        section.updateSuggestions();
         verify(mParent, never()).onItemRangeRemoved(any(TreeNode.class), anyInt(), anyInt());
         verify(mParent, never()).onItemRangeInserted(any(TreeNode.class), anyInt(), anyInt());
 
@@ -635,9 +653,9 @@
         assertEquals(snippets, getSuggestions(section));
 
         // Try to replace them with another list. Should have no effect.
-        List<SnippetArticle> newSnippets =
-                createDummySuggestions(5, TEST_CATEGORY_ID, "new");
-        section.updateSuggestions(createSourceFor(newSnippets));
+        mSuggestionsSource.setSuggestionsForCategory(
+                TEST_CATEGORY_ID, createDummySuggestions(5, TEST_CATEGORY_ID, "new"));
+        section.updateSuggestions();
 
         // All previous snippets should be in place.
         assertEquals(snippets, getSuggestions(section));
@@ -775,34 +793,19 @@
         return new OfflinePageItem(url, offlineId, "", "", "", 0, 0, 0, 0);
     }
 
-    private SuggestionsSource createSourceFor(List<SnippetArticle> suggestions) {
-        SuggestionsSource suggestionsSource = mock(SuggestionsSource.class);
-
-        // Here we don't bother checking the category id bacause section should not manipulate
-        // multiple category ids anyway.
-        when(suggestionsSource.getSuggestionsForCategory(anyInt())).thenReturn(suggestions);
-
-        return suggestionsSource;
-    }
-
-    private static void verifyAction(
+    private void verifyAction(
             SuggestionsSection section, @ContentSuggestionsAdditionalAction int action) {
-        SuggestionsSource suggestionsSource = mock(SuggestionsSource.class);
-        SuggestionsUiDelegate manager = mock(SuggestionsUiDelegate.class);
-        SuggestionsNavigationDelegate navDelegate = mock(SuggestionsNavigationDelegate.class);
-        when(manager.getSuggestionsSource()).thenReturn(suggestionsSource);
-        when(manager.getNavigationDelegate()).thenReturn(navDelegate);
-        when(manager.getEventReporter()).thenReturn(mock(SuggestionsEventReporter.class));
-
         if (action != ContentSuggestionsAdditionalAction.NONE) {
-            section.getActionItemForTesting().performAction(manager);
+            section.getActionItemForTesting().performAction(mUiDelegate);
         }
 
         verify(section.getCategoryInfo(),
                 (action == ContentSuggestionsAdditionalAction.VIEW_ALL ? times(1) : never()))
-                .performViewAllAction(navDelegate);
-        verify(suggestionsSource,
+                .performViewAllAction(mUiDelegate.getNavigationDelegate());
+
+        // noinspection unchecked -- See https://crbug.com/740162 for rationale.
+        verify(mUiDelegate.getSuggestionsSource(),
                 (action == ContentSuggestionsAdditionalAction.FETCH ? times(1) : never()))
-                .fetchSuggestions(anyInt(), any(String[].class));
+                .fetchSuggestions(anyInt(), any(String[].class), any(Callback.class));
     }
 }
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/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
index 096e952..1f0f40a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
@@ -4,16 +4,20 @@
 
 package org.chromium.chrome.browser.suggestions;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -25,15 +29,13 @@
 import android.widget.FrameLayout;
 
 import org.hamcrest.CoreMatchers;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
@@ -41,10 +43,15 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
+import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
 /**
  * Unit tests for {@link TileGroup}.
  */
@@ -63,28 +70,20 @@
     private TileGroup.Observer mTileGroupObserver;
 
     private FakeTileGroupDelegate mTileGroupDelegate;
+    private FakeImageFetcher mImageFetcher;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
+        CardsVariationParameters.setTestVariationParams(new HashMap<String, String>());
 
-        mTileGroupDelegate = new FakeTileGroupDelegate();
+        MockitoAnnotations.initMocks(this);
+        mTileGroupDelegate = spy(new FakeTileGroupDelegate());
+        mImageFetcher = new FakeImageFetcher();
     }
 
-    @Test
-    public void testInitialiseWithEmptyTileList() {
-        TileGroup tileGroup =
-                new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
-                        mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                        mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-        notifyTileUrlsAvailable();
-
-        // The TileGroup.Observer methods should be called even though no tiles are added, which is
-        // an initialisation but not real state change.
-        verify(mTileGroupObserver).onTileCountChanged();
-        verify(mTileGroupObserver).onLoadTaskCompleted();
-        verify(mTileGroupObserver).onTileDataChanged();
+    @After
+    public void tearDown() {
+        CardsVariationParameters.setTestVariationParams(null);
     }
 
     @Test
@@ -98,63 +97,104 @@
         notifyTileUrlsAvailable(URLS);
 
         verify(mTileGroupObserver).onTileCountChanged();
-        verify(mTileGroupObserver).onLoadTaskCompleted();
         verify(mTileGroupObserver).onTileDataChanged();
+
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+        assertTrue(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.FETCH_DATA));
+    }
+
+    /**
+     * Test the special case during initialisation, where we notify TileGroup.Observer of changes
+     * event though the data did not change (still empty just like before initialisation).
+     */
+    @Test
+    public void testInitialiseWithEmptyTileList() {
+        TileGroup tileGroup =
+                new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
+                        mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
+                        mock(OfflinePageBridge.class), TILE_TITLE_LINES);
+        tileGroup.startObserving(MAX_TILES_TO_FETCH);
+
+        notifyTileUrlsAvailable(/* nothing! */);
+
+        verify(mTileGroupObserver).onTileCountChanged();
+        verify(mTileGroupObserver).onTileDataChanged();
+
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+        assertTrue(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.FETCH_DATA));
     }
 
     @Test
     public void testReceiveNewTilesWithoutChanges() {
-        TileGroup tileGroup =
-                new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
-                        mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                        mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-
-        // First initialisation
-        notifyTileUrlsAvailable(URLS);
-        reset(mTileGroupObserver);
+        TileGroup tileGroup = initialiseTileGroup(URLS);
 
         // Notify the same thing. No changes so|mTileGroupObserver| should not be notified.
         notifyTileUrlsAvailable(URLS);
+
         verifyNoMoreInteractions(mTileGroupObserver);
+        verifyNoMoreInteractions(mTileGroupDelegate);
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
+    }
+
+    @Test
+    public void testReceiveNewTilesWithoutChanges_TrackLoad() {
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
+
+        // Notify the same thing. No changes so|mTileGroupObserver| should not be notified.
+        notifyTileUrlsAvailable(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+
+        verifyNoMoreInteractions(mTileGroupObserver);
+        verifyNoMoreInteractions(mTileGroupDelegate);
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
     }
 
     @Test
     public void testReceiveNewTilesWithDataChanges() {
-        TileGroup tileGroup =
-                new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
-                        mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                        mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-
-        // First initialisation
-        notifyTileUrlsAvailable(URLS);
-        reset(mTileGroupObserver);
+        TileGroup tileGroup = initialiseTileGroup(URLS);
 
         // Notify the about different URLs, but the same number. #onTileCountChanged() should not be
         // called.
         notifyTileUrlsAvailable("foo", "bar");
-        verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2
-        verify(mTileGroupObserver, never()).onLoadTaskCompleted(); // No load task the second time.
+
+        verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2.
         verify(mTileGroupObserver).onTileDataChanged(); // Data DID change.
+
+        // No load task the second time.
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
+    }
+
+    @Test
+    public void testReceiveNewTilesWithDataChanges_TrackLoad() {
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
+
+        // Notify the about different URLs, but the same number. #onTileCountChanged() should not be
+        // called.
+        notifyTileUrlsAvailable("foo", "bar");
+        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+
+        verify(mTileGroupObserver).onTileDataChanged(); // Now data DID change.
+        verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2.
+
+        // We should now have a pending task.
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+        assertTrue(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
     }
 
     @Test
     public void testReceiveNewTilesWithCountChanges() {
-        TileGroup tileGroup =
-                new TileGroup(RuntimeEnvironment.application, mock(SuggestionsUiDelegate.class),
-                        mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                        mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-
-        // First initialisation
-        notifyTileUrlsAvailable(URLS);
-        reset(mTileGroupObserver);
+        TileGroup tileGroup = initialiseTileGroup(URLS);
 
         notifyTileUrlsAvailable(URLS[0]);
+
         verify(mTileGroupObserver).onTileCountChanged(); // Tile count DID change.
-        verify(mTileGroupObserver, never()).onLoadTaskCompleted(); // No load task the second time.
         verify(mTileGroupObserver).onTileDataChanged(); // Data DID change.
+        verify(mTileGroupDelegate, never())
+                .onLoadingComplete(any(Tile[].class)); // No load task the second time.
+        assertFalse(tileGroup.isTaskPending(TileGroup.TileTask.SCHEDULE_ICON_FETCH));
     }
 
     @Test
@@ -183,6 +223,7 @@
 
         notifyTileUrlsAvailable(URLS);
         reset(mTileGroupObserver);
+
         notifyTileUrlsAvailable(URLS[0]);
 
         // Even though the data changed, the notification should not happen because we want to not
@@ -191,7 +232,23 @@
 
         // Simulating a switch from background to foreground should force the tilegrid to load the
         // new data.
-        tileGroup.onSwitchToForeground();
+        tileGroup.onSwitchToForeground(true);
+        verify(mTileGroupObserver).onTileDataChanged();
+    }
+
+    @Test
+    public void testTileLoadingWhenVisibleBlocked_2() {
+        TileGroup tileGroup = initialiseTileGroup(true, URLS);
+
+        notifyTileUrlsAvailable(URLS[0]);
+
+        // Even though the data changed, the notification should not happen because we want to not
+        // show changes to UI elements currently visible
+        verify(mTileGroupObserver, never()).onTileDataChanged();
+
+        // Simulating a switch from background to foreground should force the tilegrid to load the
+        // new data.
+        tileGroup.onSwitchToForeground(true);
         verify(mTileGroupObserver).onTileDataChanged();
     }
 
@@ -209,12 +266,13 @@
         notifyTileUrlsAvailable(URLS);
 
         // Render them to the layout.
-        tileGroup.renderTileViews(layout, false, false);
+        tileGroup.renderTileViews(layout, false);
         assertThat(layout.getChildCount(), is(2));
         assertThat(((TileView) layout.getChildAt(0)).getUrl(), is(URLS[0]));
         assertThat(((TileView) layout.getChildAt(1)).getUrl(), is(URLS[1]));
     }
 
+    /** Check for https://crbug.com/703628: handle duplicated URLs by ignoring them. */
     @Test
     public void testRenderTileViewWithDuplicatedUrl() {
         SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
@@ -229,7 +287,7 @@
         notifyTileUrlsAvailable(URLS[0], URLS[1], URLS[0]);
 
         // Render them to the layout. The duplicated URL is skipped.
-        tileGroup.renderTileViews(layout, false, false);
+        tileGroup.renderTileViews(layout, false);
         assertThat(layout.getChildCount(), is(2));
         assertThat(((TileView) layout.getChildAt(0)).getUrl(), is(URLS[0]));
         assertThat(((TileView) layout.getChildAt(1)).getUrl(), is(URLS[1]));
@@ -254,7 +312,7 @@
         layout.addView(view2);
 
         // The tiles should be updated, the old ones removed.
-        tileGroup.renderTileViews(layout, false, false);
+        tileGroup.renderTileViews(layout, false);
         assertThat(layout.getChildCount(), is(2));
         assertThat(layout.indexOfChild(view1), is(-1));
         assertThat(layout.indexOfChild(view2), is(-1));
@@ -282,7 +340,7 @@
         layout.addView(view2);
 
         // The tiles should be updated, the old ones reused.
-        tileGroup.renderTileViews(layout, false, false);
+        tileGroup.renderTileViews(layout, false);
         assertThat(layout.getChildCount(), is(2));
         assertThat(layout.getChildAt(0), CoreMatchers.<View>is(view1));
         assertThat(layout.getChildAt(1), CoreMatchers.<View>is(view2));
@@ -291,85 +349,92 @@
     }
 
     @Test
-    public void testIconLoading() {
-        SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
-        when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
-        TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate,
-                mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-        notifyTileUrlsAvailable(URLS); // Initialise the internal state to include the test tile.
-        reset(mTileGroupObserver);
+    public void testIconLoadingForInit() {
+        TileGroup tileGroup = initialiseTileGroup(URLS);
         Tile tile = tileGroup.getTiles()[0];
 
-        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.buildTileView(tile, layout, /* trackLoadTask = */ true, /* condensed = */ false);
+        // Loading complete should be delayed until the icons are done loading.
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
 
-        verify(mTileGroupObserver).onLoadTaskAdded();
+        mImageFetcher.fulfillLargeIconRequests();
 
-        ArgumentCaptor<LargeIconCallback> captor = ArgumentCaptor.forClass(LargeIconCallback.class);
-        verify(uiDelegate.getImageFetcher())
-                .makeLargeIconRequest(any(String.class), anyInt(), captor.capture());
-        for (LargeIconCallback cb : captor.getAllValues()) {
-            cb.onLargeIconAvailable(mock(Bitmap.class), Color.BLACK, /* isColorDefault = */ false);
-        }
-
-        verify(mTileGroupObserver).onLoadTaskCompleted();
-        verify(mTileGroupObserver).onTileIconChanged(tile);
-    }
-
-    @Test
-    public void testIconLoadingNoTask() {
-        SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
-        when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
-        TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate,
-                mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-        notifyTileUrlsAvailable(URLS); // Initialise the internal state to include the test tile.
-        reset(mTileGroupObserver);
-        Tile tile = tileGroup.getTiles()[0];
-
-        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.buildTileView(tile, layout, /* trackLoadTask = */ false, /* condensed = */ false);
-
-        verify(mTileGroupObserver, never()).onLoadTaskAdded();
-
-        ArgumentCaptor<LargeIconCallback> captor = ArgumentCaptor.forClass(LargeIconCallback.class);
-        verify(uiDelegate.getImageFetcher())
-                .makeLargeIconRequest(any(String.class), anyInt(), captor.capture());
-        for (LargeIconCallback cb : captor.getAllValues()) {
-            cb.onLargeIconAvailable(mock(Bitmap.class), Color.BLACK, /* isColorDefault = */ false);
-        }
-
-        verify(mTileGroupObserver, never()).onLoadTaskCompleted();
-        verify(mTileGroupObserver).onTileIconChanged(tile);
+        // The load should now be complete.
+        verify(mTileGroupDelegate).onLoadingComplete(any(Tile[].class));
+        verify(mTileGroupObserver).onTileIconChanged(eq(tile));
+        verify(mTileGroupObserver, times(URLS.length)).onTileIconChanged(any(Tile.class));
     }
 
     @Test
     public void testIconLoadingWhenTileNotRegistered() {
-        SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
-        when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
-        TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate,
-                mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                mock(OfflinePageBridge.class), TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-        reset(mTileGroupObserver);
+        TileGroup tileGroup = initialiseTileGroup();
         Tile tile = new Tile("title", URLS[0], "", 0, TileSource.POPULAR);
 
         ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
-        tileGroup.buildTileView(tile, layout, /* trackLoadTask = */ true, /* condensed = */ false);
-        verify(mTileGroupObserver).onLoadTaskAdded();
+        tileGroup.buildTileView(tile, layout, /* condensed = */ false);
 
-        ArgumentCaptor<LargeIconCallback> captor = ArgumentCaptor.forClass(LargeIconCallback.class);
-        verify(uiDelegate.getImageFetcher())
-                .makeLargeIconRequest(any(String.class), anyInt(), captor.capture());
-        captor.getValue().onLargeIconAvailable(mock(Bitmap.class), Color.BLACK, false);
+        // Ensure we run the callback for the new tile.
+        assertEquals(1, mImageFetcher.getPendingIconCallbackCount());
+        mImageFetcher.fulfillLargeIconRequests();
 
-        verify(mTileGroupObserver).onLoadTaskCompleted();
         verify(mTileGroupObserver, never()).onTileIconChanged(tile);
     }
 
+    @Test
+    public void testIconLoading_Sync() {
+        TileGroup tileGroup = initialiseTileGroup();
+        mImageFetcher.fulfillLargeIconRequests();
+        reset(mTileGroupObserver, mTileGroupDelegate);
+
+        // Notify for a second set.
+        notifyTileUrlsAvailable(URLS);
+        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
+        tileGroup.renderTileViews(layout, /* condensed: */ false);
+        mImageFetcher.fulfillLargeIconRequests();
+
+        // Data changed but no loading complete event is sent
+        verify(mTileGroupObserver).onTileDataChanged();
+        verify(mTileGroupObserver, times(URLS.length)).onTileIconChanged(any(Tile.class));
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+    }
+
+    @Test
+    public void testIconLoading_AsyncNoTrack() {
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
+        mImageFetcher.fulfillLargeIconRequests();
+        reset(mTileGroupObserver, mTileGroupDelegate);
+
+        // Notify for a second set.
+        notifyTileUrlsAvailable(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask: */ false);
+        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
+        tileGroup.renderTileViews(layout, /* condensed: */ false);
+        mImageFetcher.fulfillLargeIconRequests();
+
+        // Data changed but no loading complete event is sent (same as sync)
+        verify(mTileGroupObserver).onTileDataChanged();
+        verify(mTileGroupObserver, times(URLS.length)).onTileIconChanged(any(Tile.class));
+        verify(mTileGroupDelegate, never()).onLoadingComplete(any(Tile[].class));
+    }
+
+    @Test
+    public void testIconLoading_AsyncTrack() {
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
+        mImageFetcher.fulfillLargeIconRequests();
+        reset(mTileGroupObserver, mTileGroupDelegate);
+
+        // Notify for a second set.
+        notifyTileUrlsAvailable(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
+        tileGroup.renderTileViews(layout, /* condensed: */ false);
+        mImageFetcher.fulfillLargeIconRequests();
+
+        // Data changed but no loading complete event is sent
+        verify(mTileGroupObserver).onTileDataChanged();
+        verify(mTileGroupObserver, times(URLS.length)).onTileIconChanged(any(Tile.class));
+        verify(mTileGroupDelegate).onLoadingComplete(any(Tile[].class));
+    }
+
     /**
      * Notifies the tile group of new tiles created from the provided URLs. Requires
      * {@link TileGroup#startObserving(int)} to have been called on the tile group under test.
@@ -386,23 +451,34 @@
                 titles, urls, whitelistIconPaths, sources);
     }
 
+    /** {@link #initialiseTileGroup(boolean, String...)} override that does not defer loads. */
+    private TileGroup initialiseTileGroup(String... urls) {
+        return initialiseTileGroup(false, urls);
+    }
+
     /**
-     * Creates a mocked {@link TileView} that will return the URL of the tile it has been
-     * initialised with.
+     * @param deferLoad whether to defer the load until
+     *                  {@link TileGroup#onSwitchToForeground(boolean)} is called. Works by
+     *                  pretending that the UI is visible.
+     * @param urls URLs used to initialise the tile group.
      */
-    private static TileView createMockTileView() {
-        final TileView tileView = mock(TileView.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Tile tile = invocation.getArgument(0);
-                when(tileView.getUrl()).thenReturn(tile.getUrl());
-                return null;
-            }
-        })
-                .when(tileView)
-                .initialize(any(Tile.class), anyInt(), anyBoolean());
-        return tileView;
+    private TileGroup initialiseTileGroup(boolean deferLoad, String... urls) {
+        SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
+        when(uiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
+        when(uiDelegate.isVisible()).thenReturn(deferLoad);
+
+        TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, uiDelegate,
+                mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
+                mock(OfflinePageBridge.class), TILE_TITLE_LINES);
+        tileGroup.startObserving(MAX_TILES_TO_FETCH);
+        notifyTileUrlsAvailable(urls);
+
+        ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
+        tileGroup.renderTileViews(layout, /* condensed = */ false);
+
+        reset(mTileGroupObserver);
+        reset(mTileGroupDelegate);
+        return tileGroup;
     }
 
     private class FakeTileGroupDelegate implements TileGroup.Delegate {
@@ -426,4 +502,32 @@
         @Override
         public void destroy() {}
     }
+
+    private class FakeImageFetcher extends ImageFetcher {
+        private final List<LargeIconCallback> mCallbackList = new ArrayList<>();
+
+        public FakeImageFetcher() {
+            super(null, null, null);
+        }
+
+        @Override
+        public void makeLargeIconRequest(String url, int size, LargeIconCallback callback) {
+            mCallbackList.add(callback);
+        }
+
+        public void fulfillLargeIconRequests(Bitmap bitmap, int color, boolean isColorDefault) {
+            for (LargeIconCallback callback : mCallbackList) {
+                callback.onLargeIconAvailable(bitmap, color, isColorDefault);
+            }
+            mCallbackList.clear();
+        }
+
+        public int getPendingIconCallbackCount() {
+            return mCallbackList.size();
+        }
+
+        public void fulfillLargeIconRequests() {
+            fulfillLargeIconRequests(mock(Bitmap.class), Color.BLACK, false);
+        }
+    }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index e0646f85..b5ecf04c 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -511,8 +511,8 @@
   <message name="IDS_FILE_BROWSER_REMOVE_FOLDER_SHORTCUT_BUTTON_LABEL" desc="Menu item label, unpinning the selected folder from the left nav.">
     Remove shortcut
   </message>
-  <message name="IDS_FILE_BROWSER_SHARE_BUTTON_LABEL" desc="Menu item label, showing dialog to share the selected file.">
-    Share
+  <message name="IDS_FILE_BROWSER_SHARE_BUTTON_LABEL" desc="Menu item's label, showing dialog to share the selected Google Drive files. This message is also used as a tooltip label and a spoken feedback label of a button which also shows the dialog to share the files. The translation should be consistent with the sharing dialog's title in Google Drive Web UI.">
+    Share with others
   </message>
   <message name="IDS_FILE_BROWSER_TOGGLE_HIDDEN_FILES_COMMAND_LABEL" desc="Label for menu or button with checkmark that toggles visibility of hidden files.">
     Show hidden files
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/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 1991bbc3..98885438c 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2571,8 +2571,8 @@
     <message name="IDS_SETTINGS_CHANGE_PICTURE_PREVIEW_ALT" desc="Alt text for the big preview of user image.">
       User image preview
     </message>
-    <message name="IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_TEXT" desc="Author label.">
-      Photo by
+    <message name="IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_CREDIT_TEXT" desc="Label in the profile picture picker for the photo credit for the selected image.">
+      Photo by <ph name="NAME">$1<ex>John Doe</ex></ph>
     </message>
     <message name="IDS_SETTINGS_CHANGE_PICTURE_PROFILE_LOADING_PHOTO" desc="The text on the loading stub for Google profile image.">
       Google Profile photo (loading)
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d2ad4bf2..ff0b081 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,18 @@
      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)
+
+    {"enable-resource-load-scheduler",
+     flag_descriptions::kResourceLoadSchedulerName,
+     flag_descriptions::kResourceLoadSchedulerDescription, kOsAll,
+     FEATURE_VALUE_TYPE(features::kResourceLoadScheduler)},
+
     // 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/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index da16a3d..f90fec1 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -323,7 +323,9 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint j_category_id,
-    const JavaParamRef<jobjectArray>& j_displayed_suggestions) {
+    const JavaParamRef<jobjectArray>& j_displayed_suggestions,
+    const JavaParamRef<jobject>& j_callback) {
+  ScopedJavaGlobalRef<jobject> callback(j_callback);
   std::vector<std::string> known_suggestion_ids;
   AppendJavaStringArrayToStringVector(env, j_displayed_suggestions,
                                       &known_suggestion_ids);
@@ -334,7 +336,7 @@
       std::set<std::string>(known_suggestion_ids.begin(),
                             known_suggestion_ids.end()),
       base::Bind(&NTPSnippetsBridge::OnSuggestionsFetched,
-                 weak_ptr_factory_.GetWeakPtr(), category));
+                 weak_ptr_factory_.GetWeakPtr(), callback, category));
 }
 
 void NTPSnippetsBridge::FetchContextualSuggestions(
@@ -456,14 +458,14 @@
 }
 
 void NTPSnippetsBridge::OnSuggestionsFetched(
+    const ScopedJavaGlobalRef<jobject>& callback,
     Category category,
     ntp_snippets::Status status,
     std::vector<ContentSuggestion> suggestions) {
   // TODO(fhorschig, dgn): Allow refetch or show notification acc. to status.
   JNIEnv* env = AttachCurrentThread();
-  Java_SnippetsBridge_onMoreSuggestions(
-      env, bridge_, category.id(),
-      ToJavaSuggestionList(env, category, suggestions));
+  RunCallbackAndroid(callback,
+                     ToJavaSuggestionList(env, category, suggestions));
 }
 
 // static
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index 16770059..0860da0 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -73,7 +73,8 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       jint j_category_id,
-      const base::android::JavaParamRef<jobjectArray>& j_displayed_suggestions);
+      const base::android::JavaParamRef<jobjectArray>& j_displayed_suggestions,
+      const base::android::JavaParamRef<jobject>& j_callback);
 
   void FetchContextualSuggestions(
       JNIEnv* env,
@@ -119,6 +120,7 @@
   void OnImageFetched(base::android::ScopedJavaGlobalRef<jobject> callback,
                       const gfx::Image& image);
   void OnSuggestionsFetched(
+      const base::android::ScopedJavaGlobalRef<jobject>& callback,
       ntp_snippets::Category category,
       ntp_snippets::Status status,
       std::vector<ntp_snippets::ContentSuggestion> suggestions);
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index dba05a2..847fb27 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -144,10 +144,6 @@
         base::Bind(&ShortcutHelper::FetchSplashScreenImage, web_contents,
                    info.splash_image_url, info.ideal_splash_image_size_in_px,
                    info.minimum_splash_image_size_in_px, webapp_id));
-    GooglePlayInstallState state =
-        ChromeWebApkHost::GetGooglePlayInstallState();
-    if (state != GooglePlayInstallState::SUPPORTED)
-      webapk::TrackGooglePlayInstallState(state);
     return;
   }
   AddShortcutWithSkBitmap(info, webapp_id, icon_bitmap);
@@ -162,7 +158,6 @@
     const WebApkInstallService::FinishCallback& callback) {
   WebApkInstallService::Get(web_contents->GetBrowserContext())
       ->InstallAsync(info, primary_icon_bitmap, badge_icon_bitmap, callback);
-  webapk::TrackGooglePlayInstallState(GooglePlayInstallState::SUPPORTED);
 }
 
 void ShortcutHelper::ShowWebApkInstallInProgressToast() {
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
index 30cc4440..5b35f4f 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
@@ -58,6 +58,13 @@
   }
 }
 
+SkColor GetSecurityChipColor(SecurityLevel level,
+                             bool offline_page,
+                             const ColorScheme& color_scheme) {
+  return offline_page ? color_scheme.url_emphasized
+                      : GetSchemeColor(level, color_scheme);
+}
+
 void setEmphasis(vr_shell::RenderTextWrapper* render_text,
                  bool emphasis,
                  const gfx::Range& range,
@@ -81,7 +88,6 @@
     bool web_vr,
     const base::Callback<void(UiUnsupportedMode)>& failure_callback)
     : has_back_button_(!web_vr),
-      has_security_chip_(false),
       failure_callback_(failure_callback) {}
 
 UrlBarTexture::~UrlBarTexture() = default;
@@ -220,8 +226,8 @@
 
   // Site security state icon.
   left_edge += kFieldSpacing;
-  if (state_.security_level != security_state::NONE &&
-      state_.vector_icon != nullptr) {
+  if ((state_.security_level != security_state::NONE || state_.offline_page) &&
+      state_.vector_icon != nullptr && state_.should_display_url) {
     gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconSize / 2,
                            kSecurityIconSize, kSecurityIconSize);
     canvas->save();
@@ -230,7 +236,8 @@
     float icon_scale = kSecurityIconSize / GetDefaultSizeOfVectorIcon(icon);
     canvas->scale(icon_scale, icon_scale);
     PaintVectorIcon(&gfx_canvas, icon,
-                    GetSchemeColor(state_.security_level, color_scheme()));
+                    GetSecurityChipColor(state_.security_level,
+                                         state_.offline_page, color_scheme()));
     canvas->restore();
 
     security_hit_region_ = icon_region;
@@ -239,14 +246,21 @@
 
   canvas->restore();
 
-  // Draw security chip text (eg. "Not secure") next to the security icon.
-  if (has_security_chip_ && state_.should_display_url) {
+  // The security chip text consumes a significant percentage of URL bar text
+  // space, so they are currently disabled (see crbug.com/734206). The offline
+  // chip is an exception, and must be shown (see crbug.com/735770).
+  bool draw_security_chip = state_.offline_page;
+
+  // Possibly draw security chip text (eg. "Not secure") next to the security
+  // icon.
+  if (draw_security_chip && state_.should_display_url) {
     float chip_max_width = kWidth - left_edge - kUrlRightMargin;
     gfx::Rect text_bounds(ToPixels(left_edge), 0, ToPixels(chip_max_width),
                           ToPixels(kHeight));
 
     int pixel_font_height = texture_size.height() * kFontHeight / kHeight;
-    SkColor chip_color = GetSchemeColor(state_.security_level, color_scheme());
+    SkColor chip_color = GetSecurityChipColor(
+        state_.security_level, state_.offline_page, color_scheme());
     const base::string16& chip_text = state_.secure_verbose_text;
     DCHECK(!chip_text.empty());
 
@@ -300,6 +314,7 @@
 void UrlBarTexture::RenderUrl(const gfx::Size& texture_size,
                               const gfx::Rect& bounds) {
   url::Parsed parsed;
+
   const base::string16 text = url_formatter::FormatUrl(
       state_.gurl, url_formatter::kFormatUrlOmitAll, net::UnescapeRule::NORMAL,
       &parsed, nullptr, nullptr);
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.h b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
index bc24715..ed721e5 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.h
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
@@ -81,7 +81,6 @@
 
   GURL last_drawn_gurl_;
   bool has_back_button_ = true;
-  bool has_security_chip_ = true;
   security_state::SecurityLevel last_drawn_security_level_;
   base::Callback<void(UiUnsupportedMode)> failure_callback_;
   gfx::RectF security_hit_region_ = gfx::RectF(0, 0, 0, 0);
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.cc b/chrome/browser/android/webapk/chrome_webapk_host.cc
index 8eab89df..f18514d 100644
--- a/chrome/browser/android/webapk/chrome_webapk_host.cc
+++ b/chrome/browser/android/webapk/chrome_webapk_host.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/android/webapk/chrome_webapk_host.h"
 
+#include "base/feature_list.h"
 #include "chrome/browser/android/chrome_feature_list.h"
 #include "components/variations/variations_associated_data.h"
 #include "jni/ChromeWebApkHost_jni.h"
@@ -23,15 +24,7 @@
 
 // static
 bool ChromeWebApkHost::CanInstallWebApk() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  return Java_ChromeWebApkHost_canInstallWebApk(env);
-}
-
-// static
-GooglePlayInstallState ChromeWebApkHost::GetGooglePlayInstallState() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  return static_cast<GooglePlayInstallState>(
-      Java_ChromeWebApkHost_getGooglePlayInstallState(env));
+  return base::FeatureList::IsEnabled(chrome::android::kImprovedA2HS);
 }
 
 // static
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.h b/chrome/browser/android/webapk/chrome_webapk_host.h
index dfb1113..7505772 100644
--- a/chrome/browser/android/webapk/chrome_webapk_host.h
+++ b/chrome/browser/android/webapk/chrome_webapk_host.h
@@ -9,19 +9,6 @@
 
 #include "base/macros.h"
 
-// This enum is used to back a UMA histogram, and must be treated as
-// append-only.
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser
-enum class GooglePlayInstallState {
-  SUPPORTED = 0,
-  DISABLED_OTHER = 1,
-  NO_PLAY_SERVICES = 2,
-  // Deprecated: DISABLED_BY_VARIATIONS = 3,
-  DISABLED_BY_PLAY = 4,
-  MAX = 5
-};
-
 // ChromeWebApkHost is the C++ counterpart of org.chromium.chrome.browser's
 // ChromeWebApkHost in Java.
 class ChromeWebApkHost {
@@ -32,9 +19,6 @@
   // Returns whether installing WebApk is possible.
   static bool CanInstallWebApk();
 
-  // Returns the state of installing a WebAPK from Google Play.
-  static GooglePlayInstallState GetGooglePlayInstallState();
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ChromeWebApkHost);
 };
diff --git a/chrome/browser/android/webapk/webapk_metrics.cc b/chrome/browser/android/webapk/webapk_metrics.cc
index fe92fb24..f6c2b9c 100644
--- a/chrome/browser/android/webapk/webapk_metrics.cc
+++ b/chrome/browser/android/webapk/webapk_metrics.cc
@@ -10,7 +10,6 @@
 
 namespace webapk {
 
-const char kGooglePlayInstallState[] = "WebApk.Install.GooglePlayInstallState";
 const char kInstallDurationHistogram[] = "WebApk.Install.InstallDuration";
 const char kInstallEventHistogram[] = "WebApk.Install.InstallEvent";
 const char kInstallSourceHistogram[] = "WebApk.Install.InstallSource";
@@ -42,9 +41,4 @@
   UMA_HISTOGRAM_ENUMERATION(kUserActionHistogram, event, USER_ACTION_MAX);
 }
 
-void TrackGooglePlayInstallState(GooglePlayInstallState state) {
-  UMA_HISTOGRAM_ENUMERATION(kGooglePlayInstallState, static_cast<int>(state),
-                            static_cast<int>(GooglePlayInstallState::MAX));
-}
-
 }  // namespace webapk
diff --git a/chrome/browser/android/webapk/webapk_metrics.h b/chrome/browser/android/webapk/webapk_metrics.h
index ad5ff53..7ddd37bf 100644
--- a/chrome/browser/android/webapk/webapk_metrics.h
+++ b/chrome/browser/android/webapk/webapk_metrics.h
@@ -9,8 +9,6 @@
 class TimeDelta;
 }
 
-enum class GooglePlayInstallState;
-
 namespace webapk {
 
 // Keep these enums up to date with tools/metrics/histograms/histograms.xml.
@@ -63,14 +61,6 @@
 void TrackInstallInfoBarShown(InfoBarShown event);
 void TrackUserAction(UserAction event);
 
-// On web app and WebAPK installation records whether a WebAPK could be
-// installed via the Google Play flow. If not, records why the WebAPK could not
-// be installed via the Google Play flow (and a web app was added to the
-// homescreen instead).
-// Warning: This metric is recorded whenever a site is added to the homescreeen
-// as a web app, not just for sites with a WebAPK compatible Web Manifest.
-void TrackGooglePlayInstallState(GooglePlayInstallState state);
-
 };  // namespace webapk
 
 #endif  // CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_METRICS_H_
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index f4a522d9..dbaf3a31 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -7,30 +7,19 @@
 #include <memory>
 #include <string>
 
-#include "base/callback_forward.h"
-#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
 #include "chrome/browser/installable/installable_manager.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/browser/service_worker/embedded_worker_test_helper.h"
-#include "content/browser/service_worker/service_worker_context_core.h"
-#include "content/common/service_worker/service_worker_status_code.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/manifest.h"
-#include "content/test/test_web_contents.h"
-#include "net/http/http_status_code.h"
 #include "third_party/WebKit/public/platform/WebDisplayMode.h"
 #include "ui/gfx/image/image_unittest_util.h"
 #include "url/gurl.h"
@@ -39,72 +28,15 @@
 
 const char* kWebApplicationInfoTitle = "Meta Title";
 const char* kDefaultManifestUrl = "https://www.example.com/manifest.json";
+const char* kDefaultIconUrl = "https://www.example.com/icon.png";
 const char* kDefaultManifestName = "Default Name";
 const char* kDefaultManifestShortName = "Default Short Name";
 const char* kDefaultStartUrl = "https://www.example.com/index.html";
 const blink::WebDisplayMode kDefaultManifestDisplayMode =
     blink::kWebDisplayModeStandalone;
+const int kIconSizePx = 144;
 
-// WebContents subclass which mocks out image and manifest fetching.
-class MockWebContents : public content::TestWebContents {
- public:
-  explicit MockWebContents(content::BrowserContext* browser_context)
-      : content::TestWebContents(browser_context),
-        should_image_time_out_(false),
-        should_manifest_time_out_(false) {}
-
-  ~MockWebContents() override {}
-
-  void SetManifest(const GURL& manifest_url,
-                   const content::Manifest& manifest) {
-    manifest_url_ = manifest_url;
-    manifest_ = manifest;
-  }
-
-  int DownloadImage(const GURL& url,
-                    bool is_favicon,
-                    uint32_t max_bitmap_size,
-                    bool bypass_cache,
-                    const ImageDownloadCallback& callback) override {
-    if (should_image_time_out_)
-      return 0;
-
-    const int kIconSizePx = 144;
-    SkBitmap icon = gfx::test::CreateBitmap(kIconSizePx, kIconSizePx);
-    std::vector<SkBitmap> icons(1u, icon);
-    std::vector<gfx::Size> pixel_sizes(1u, gfx::Size(kIconSizePx, kIconSizePx));
-    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
-        ->PostTask(FROM_HERE, base::Bind(callback, 0, net::HTTP_OK, url, icons,
-                                         pixel_sizes));
-    return 0;
-  }
-
-  void GetManifest(const GetManifestCallback& callback) override {
-    if (should_manifest_time_out_)
-      return;
-
-    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
-        ->PostTask(FROM_HERE, base::Bind(callback, manifest_url_, manifest_));
-  }
-
-  void SetShouldImageTimeOut(bool should_time_out) {
-    should_image_time_out_ = should_time_out;
-  }
-
-  void SetShouldManifestTimeOut(bool should_time_out) {
-    should_manifest_time_out_ = should_time_out;
-  }
-
- private:
-  GURL manifest_url_;
-  content::Manifest manifest_;
-  bool should_image_time_out_;
-  bool should_manifest_time_out_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockWebContents);
-};
-
-// Tracks which of the AddToHomescreenDataFetcher::Observer callbacks have been
+// Tracks which of the AddToHomescreenDataFetcher::Observer methods have been
 // called.
 class ObserverWaiter : public AddToHomescreenDataFetcher::Observer {
  public:
@@ -126,12 +58,16 @@
   }
 
   void OnDidDetermineWebApkCompatibility(bool is_webapk_compatible) override {
+    // This should only be called once.
+    EXPECT_FALSE(determined_webapk_compatibility_);
     EXPECT_FALSE(title_available_);
     determined_webapk_compatibility_ = true;
     is_webapk_compatible_ = is_webapk_compatible;
   }
 
   void OnUserTitleAvailable(const base::string16& title) override {
+    // This should only be called once.
+    EXPECT_FALSE(title_available_);
     EXPECT_FALSE(data_available_);
     title_available_ = true;
     title_ = title;
@@ -140,6 +76,8 @@
   void OnDataAvailable(const ShortcutInfo& info,
                        const SkBitmap& primary_icon,
                        const SkBitmap& badge_icon) override {
+    // This should only be called once.
+    EXPECT_FALSE(data_available_);
     EXPECT_TRUE(title_available_);
     data_available_ = true;
     if (!quit_closure_.is_null())
@@ -169,10 +107,6 @@
   return base::NullableString16(base::UTF8ToUTF16(value), false);
 }
 
-content::Manifest BuildEmptyManifest() {
-  return content::Manifest();
-}
-
 // Builds WebAPK compatible content::Manifest.
 content::Manifest BuildDefaultManifest() {
   content::Manifest manifest;
@@ -185,7 +119,7 @@
   primary_icon.type = base::ASCIIToUTF16("image/png");
   primary_icon.sizes.push_back(gfx::Size(144, 144));
   primary_icon.purpose.push_back(content::Manifest::Icon::IconPurpose::ANY);
-  primary_icon.src = GURL("https://www.google.com/image.png");
+  primary_icon.src = GURL(kDefaultIconUrl);
   manifest.icons.push_back(primary_icon);
 
   return manifest;
@@ -193,6 +127,79 @@
 
 }  // anonymous namespace
 
+class TestInstallableManager : public InstallableManager {
+ public:
+  explicit TestInstallableManager(content::WebContents* web_contents)
+      : InstallableManager(web_contents) {}
+
+  void GetData(const InstallableParams& params,
+               const InstallableCallback& callback) override {
+    if (should_manifest_time_out_ ||
+        (params.check_installable && should_installable_time_out_)) {
+      return;
+    }
+
+    InstallableStatusCode code = NO_ERROR_DETECTED;
+    bool is_installable = is_installable_;
+    if (params.fetch_valid_primary_icon && !primary_icon_) {
+      code = NO_ACCEPTABLE_ICON;
+      is_installable = false;
+    } else if (params.check_installable) {
+      if (!IsManifestValidForWebApp(manifest_)) {
+        code = valid_manifest_->error;
+        is_installable = false;
+      } else if (!is_installable_) {
+        code = NOT_OFFLINE_CAPABLE;
+        is_installable = false;
+      }
+    }
+
+    callback.Run(
+        {code, GURL(kDefaultManifestUrl), manifest_,
+         params.fetch_valid_primary_icon ? primary_icon_url_ : GURL(),
+         params.fetch_valid_primary_icon ? primary_icon_.get() : nullptr,
+         params.fetch_valid_badge_icon ? badge_icon_url_ : GURL(),
+         params.fetch_valid_badge_icon ? badge_icon_.get() : nullptr,
+         params.check_installable ? is_installable : false});
+  }
+
+  void SetInstallable(bool is_installable) { is_installable_ = is_installable; }
+
+  void SetManifest(const content::Manifest& manifest) {
+    manifest_ = manifest;
+
+    if (!manifest.icons.empty()) {
+      primary_icon_url_ = manifest_.icons[0].src;
+      primary_icon_.reset(
+          new SkBitmap(gfx::test::CreateBitmap(kIconSizePx, kIconSizePx)));
+
+      badge_icon_url_ = manifest_.icons[0].src;
+      badge_icon_.reset(
+          new SkBitmap(gfx::test::CreateBitmap(kIconSizePx, kIconSizePx)));
+    }
+  }
+
+  void SetShouldManifestTimeOut(bool should_time_out) {
+    should_manifest_time_out_ = should_time_out;
+  }
+
+  void SetShouldInstallableTimeOut(bool should_time_out) {
+    should_installable_time_out_ = should_time_out;
+  }
+
+ private:
+  content::Manifest manifest_;
+  GURL primary_icon_url_;
+  GURL badge_icon_url_;
+  std::unique_ptr<SkBitmap> primary_icon_;
+  std::unique_ptr<SkBitmap> badge_icon_;
+
+  bool is_installable_ = true;
+
+  bool should_manifest_time_out_ = false;
+  bool should_installable_time_out_ = false;
+};
+
 // Tests AddToHomescreenDataFetcher. These tests should be browser tests but
 // Android does not support browser tests yet (crbug.com/611756).
 class AddToHomescreenDataFetcherTest : public ChromeRenderViewHostTestHarness {
@@ -206,23 +213,15 @@
     ASSERT_TRUE(profile()->CreateHistoryService(false, true));
     profile()->CreateFaviconService();
 
-    embedded_worker_test_helper_.reset(
-        new content::EmbeddedWorkerTestHelper(base::FilePath()));
-
-    scoped_refptr<content::SiteInstance> site_instance =
-        content::SiteInstance::Create(browser_context());
-    site_instance->GetProcess()->Init();
-    MockWebContents* mock_web_contents = new MockWebContents(browser_context());
-    mock_web_contents->Init(content::WebContents::CreateParams(
-        browser_context(), std::move(site_instance)));
-    InstallableManager::CreateForWebContents(mock_web_contents);
-    SetContents(mock_web_contents);
-    NavigateAndCommit(GURL(kDefaultStartUrl));
-  }
-
-  void TearDown() override {
-    embedded_worker_test_helper_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
+    // Manually inject the TestInstallableManager as a "InstallableManager"
+    // WebContentsUserData. We can't directly call ::CreateForWebContents due to
+    // typing issues since TestInstallableManager doesn't directly inherit from
+    // WebContentsUserData.
+    web_contents()->SetUserData(
+        TestInstallableManager::UserDataKey(),
+        base::WrapUnique(new TestInstallableManager(web_contents())));
+    installable_manager_ = static_cast<TestInstallableManager*>(
+        web_contents()->GetUserData(TestInstallableManager::UserDataKey()));
   }
 
   std::unique_ptr<AddToHomescreenDataFetcher> BuildFetcher(
@@ -232,51 +231,47 @@
         web_contents(), 1, 1, 1, 1, 1, 500, check_webapk_compatible, observer);
   }
 
-  // Set the manifest to be returned as a result of WebContents::GetManifest().
-  void SetManifest(const GURL& manifest_url,
-                   const content::Manifest& manifest) {
-    MockWebContents* mock_web_contents =
-        static_cast<MockWebContents*>(web_contents());
-    mock_web_contents->SetManifest(manifest_url, manifest);
+  void RunFetcher(AddToHomescreenDataFetcher* fetcher,
+                  ObserverWaiter& waiter,
+                  const char* expected_title,
+                  blink::WebDisplayMode display_mode,
+                  bool is_webapk_compatible) {
+    WebApplicationInfo web_application_info;
+    web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+
+    fetcher->OnDidGetWebApplicationInfo(web_application_info);
+    waiter.WaitForDataAvailable();
+
+    EXPECT_EQ(check_webapk_compatibility(),
+              waiter.determined_webapk_compatibility());
+    EXPECT_EQ(is_webapk_compatible, waiter.is_webapk_compatible());
+    EXPECT_TRUE(waiter.title_available());
+    EXPECT_TRUE(base::EqualsASCII(waiter.title(), expected_title));
+    EXPECT_TRUE(
+        base::EqualsASCII(fetcher->shortcut_info().user_title, expected_title));
+    EXPECT_EQ(display_mode, fetcher->shortcut_info().display);
   }
 
-  void SetShouldImageTimeOut(bool should_time_out) {
-    MockWebContents* mock_web_contents =
-        static_cast<MockWebContents*>(web_contents());
-    mock_web_contents->SetShouldImageTimeOut(should_time_out);
+  void SetManifest(const content::Manifest& manifest) {
+    installable_manager_->SetManifest(manifest);
+  }
+
+  void SetInstallable(bool is_installable) {
+    installable_manager_->SetInstallable(is_installable);
   }
 
   void SetShouldManifestTimeOut(bool should_time_out) {
-    MockWebContents* mock_web_contents =
-        static_cast<MockWebContents*>(web_contents());
-    mock_web_contents->SetShouldManifestTimeOut(should_time_out);
+    installable_manager_->SetShouldManifestTimeOut(should_time_out);
   }
 
-  // Registers service worker at |url|. Blocks till the service worker is
-  // registered.
-  void RegisterServiceWorker(const GURL& url) {
-    base::RunLoop run_loop;
-    embedded_worker_test_helper_->context()->RegisterServiceWorker(
-        GURL(url.spec() + "/service_worker.js"),
-        content::ServiceWorkerRegistrationOptions(url), nullptr,
-        base::Bind(&AddToHomescreenDataFetcherTest::OnServiceWorkerRegistered,
-                   base::Unretained(this), run_loop.QuitClosure()));
+  void SetShouldInstallableTimeOut(bool should_time_out) {
+    installable_manager_->SetShouldInstallableTimeOut(should_time_out);
   }
 
+  virtual bool check_webapk_compatibility() { return true; }
+
  private:
-  // Callback for RegisterServiceWorker() for when service worker registration
-  // has completed.
-  void OnServiceWorkerRegistered(const base::Closure& callback,
-                                 content::ServiceWorkerStatusCode status,
-                                 const std::string& status_message,
-                                 int64_t registration_id) {
-    ASSERT_EQ(content::SERVICE_WORKER_OK, status)
-        << content::ServiceWorkerStatusToString(status);
-    callback.Run();
-  }
-
-  std::unique_ptr<content::EmbeddedWorkerTestHelper>
-      embedded_worker_test_helper_;
+  TestInstallableManager* installable_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTest);
 };
@@ -298,155 +293,198 @@
 
   // The value of |check_webapk_compatible| used when building the
   // AddToHomescreenDataFetcher.
-  bool check_webapk_compatibility() { return GetParam(); }
+  bool check_webapk_compatibility() override { return GetParam(); }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTestCommon);
 };
 
-// Checks that AddToHomescreenDataFetcher::Observer::OnUserTitleAvailable() is
-// called when the web manifest returned is empty. The add-to-homescreen dialog
-// makes the dialog's text field editable once OnUserTitleAvailable() is called.
 TEST_P(AddToHomescreenDataFetcherTestCommon, EmptyManifest) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+  // Check that an empty manifest has the appropriate methods run.
+  ObserverWaiter waiter;
+  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+  RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+             blink::kWebDisplayModeBrowser, false);
+}
 
-  SetManifest(GURL(kDefaultManifestUrl), BuildEmptyManifest());
+TEST_P(AddToHomescreenDataFetcherTestCommon, NoIconManifest) {
+  // Test a manifest with no icons. This should use the short name and have
+  // a generated icon (empty icon url).
+  content::Manifest manifest = BuildDefaultManifest();
+  manifest.icons.clear();
+  SetManifest(manifest);
 
   ObserverWaiter waiter;
   std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
+  RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName,
+             blink::kWebDisplayModeStandalone, false);
 
-  EXPECT_EQ(check_webapk_compatibility(),
-            waiter.determined_webapk_compatibility());
-  EXPECT_FALSE(waiter.is_webapk_compatible());
-  EXPECT_TRUE(waiter.title_available());
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
+  EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty());
+  EXPECT_TRUE(fetcher->badge_icon().drawsNothing());
+  EXPECT_TRUE(fetcher->shortcut_info().best_badge_icon_url.is_empty());
 }
 
-// Test that when the manifest provides Manifest::short_name but not
-// Manifest::name that Manifest::short_name is used as the name instead of
-// WebApplicationInfo::title.
+TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) {
+  // Check that the AddToHomescreenDataFetcher::Observer methods are called
+  // if the first call to InstallableManager::GetData() times out. This should
+  // fall back to the metadata title and have an empty icon.
+  SetShouldManifestTimeOut(true);
+  SetManifest(BuildDefaultManifest());
+
+  // Check a site with no offline-capable service worker.
+  SetInstallable(false);
+  ObserverWaiter waiter;
+  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+  RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+             blink::kWebDisplayModeBrowser, false);
+
+  EXPECT_TRUE(fetcher->primary_icon().drawsNothing());
+  EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty());
+}
+
+TEST_F(AddToHomescreenDataFetcherTest, ServiceWorkerCheckTimesOut) {
+  // Check that the AddToHomescreenDataFetcher::Observer methods are called if
+  // the service worker check times out on a page that is installable (i.e. it's
+  // taken too long). This should use the short_name and icon from the manifest,
+  // but not be WebAPK-compatible. Only relevant when checking WebAPK
+  // compatibility.
+  SetManifest(BuildDefaultManifest());
+  SetShouldInstallableTimeOut(true);
+
+  ObserverWaiter waiter;
+  std::unique_ptr<AddToHomescreenDataFetcher> fetcher =
+      BuildFetcher(true, &waiter);
+  RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName,
+             blink::kWebDisplayModeStandalone, false);
+
+  EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+  EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+            GURL(kDefaultIconUrl));
+}
+
+TEST_P(AddToHomescreenDataFetcherTestCommon, InstallableManifest) {
+  // Test a site that has an offline-capable service worker.
+  content::Manifest manifest(BuildDefaultManifest());
+  SetManifest(manifest);
+
+  ObserverWaiter waiter;
+  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+  RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName,
+             blink::kWebDisplayModeStandalone, check_webapk_compatibility());
+
+  // There should always be a primary icon.
+  EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+  EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+            GURL(kDefaultIconUrl));
+
+  // Check that the badge icon is requested only when AddToHomescreenDataFetcher
+  // checks for WebAPK compatibility.
+  if (check_webapk_compatibility()) {
+    EXPECT_FALSE(fetcher->badge_icon().drawsNothing());
+    EXPECT_EQ(fetcher->shortcut_info().best_badge_icon_url,
+              GURL(kDefaultIconUrl));
+  } else {
+    EXPECT_TRUE(fetcher->badge_icon().drawsNothing());
+    EXPECT_TRUE(fetcher->shortcut_info().best_badge_icon_url.is_empty());
+  }
+}
+
 TEST_P(AddToHomescreenDataFetcherTestCommon,
-       ManifestShortNameClobbersWebApplicationName) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+       ManifestNameClobbersWebApplicationName) {
+  // Test that when the manifest provides Manifest::name but not
+  // Manifest::short_name that Manifest::name is used as the title.
+  {
+    // Check the case where we have no icons.
+    content::Manifest manifest = BuildDefaultManifest();
+    manifest.icons.clear();
+    manifest.short_name = base::NullableString16();
+    SetManifest(manifest);
+
+    ObserverWaiter waiter;
+    std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+    RunFetcher(fetcher.get(), waiter, kDefaultManifestName,
+               blink::kWebDisplayModeStandalone, false);
+
+    EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty());
+    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
+                                  kDefaultManifestName));
+  }
 
   content::Manifest manifest(BuildDefaultManifest());
-  manifest.name = base::NullableString16();
+  manifest.short_name = base::NullableString16();
+  SetManifest(manifest);
 
-  RegisterServiceWorker(GURL(kDefaultStartUrl));
-  SetManifest(GURL(kDefaultManifestUrl), manifest);
+  {
+    // Check a site with no offline-capable service worker.
+    SetInstallable(false);
+    ObserverWaiter waiter;
+    std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+    RunFetcher(fetcher.get(), waiter, kDefaultManifestName,
+               blink::kWebDisplayModeStandalone, false);
 
-  ObserverWaiter waiter;
-  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
+    EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+    EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+              GURL(kDefaultIconUrl));
+    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
+                                  kDefaultManifestName));
+  }
 
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName));
-  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
-                                kDefaultManifestShortName));
+  {
+    // Check a site where we time out waiting for the service worker.
+    SetShouldInstallableTimeOut(true);
+    ObserverWaiter waiter;
+    std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+    RunFetcher(fetcher.get(), waiter, kDefaultManifestName,
+               blink::kWebDisplayModeStandalone, false);
+
+    EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+    EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+              GURL(kDefaultIconUrl));
+    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
+                                  kDefaultManifestName));
+  }
+
+  {
+    // Check a site with an offline-capaable service worker.
+    SetInstallable(true);
+    SetShouldInstallableTimeOut(false);
+    ObserverWaiter waiter;
+    std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
+    RunFetcher(fetcher.get(), waiter, kDefaultManifestName,
+               blink::kWebDisplayModeStandalone, check_webapk_compatibility());
+
+    EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+    EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+              GURL(kDefaultIconUrl));
+    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
+                                  kDefaultManifestName));
+  }
 }
 
-// Test that when the manifest does not provide either Manifest::short_name nor
-// Manifest::name that:
-// - The page is not WebAPK compatible.
-// - WebApplicationInfo::title is used as the "name".
 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestNoNameNoShortName) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
-
+  // Test that when the manifest does not provide either Manifest::short_name
+  // nor Manifest::name that:
+  //  - The page is not WebAPK compatible.
+  //  - WebApplicationInfo::title is used as the "name".
+  //  - We still use the icons from the manifest.
   content::Manifest manifest(BuildDefaultManifest());
   manifest.name = base::NullableString16();
   manifest.short_name = base::NullableString16();
 
-  RegisterServiceWorker(GURL(kDefaultStartUrl));
-  SetManifest(GURL(kDefaultManifestUrl), manifest);
-
+  // Check the case where we don't time out waiting for the service worker.
+  SetManifest(manifest);
   ObserverWaiter waiter;
   std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
+  RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+             blink::kWebDisplayModeStandalone, false);
 
-  EXPECT_EQ(check_webapk_compatibility(),
-            waiter.determined_webapk_compatibility());
-  EXPECT_FALSE(waiter.is_webapk_compatible());
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
   EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
                                 kWebApplicationInfoTitle));
-}
-
-// Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
-// when the manifest fetch times out.
-TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
-
-  RegisterServiceWorker(GURL(kDefaultStartUrl));
-  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
-  SetShouldManifestTimeOut(true);
-  SetShouldImageTimeOut(false);
-
-  ObserverWaiter waiter;
-  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
-
-  EXPECT_EQ(check_webapk_compatibility(),
-            waiter.determined_webapk_compatibility());
-  EXPECT_FALSE(waiter.is_webapk_compatible());
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
-  EXPECT_TRUE(waiter.title_available());
-}
-
-// Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
-// when the image fetch times out.
-TEST_P(AddToHomescreenDataFetcherTestCommon, ImageFetchTimesOut) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
-
-  RegisterServiceWorker(GURL(kDefaultStartUrl));
-  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
-  SetShouldManifestTimeOut(false);
-  SetShouldImageTimeOut(true);
-
-  ObserverWaiter waiter;
-  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
-
-  EXPECT_EQ(check_webapk_compatibility(),
-            waiter.determined_webapk_compatibility());
-  EXPECT_FALSE(waiter.is_webapk_compatible());
-  EXPECT_TRUE(waiter.title_available());
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle));
-}
-
-// Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
-// when the service worker check times out.
-TEST_P(AddToHomescreenDataFetcherTestCommon, ServiceWorkerCheckTimesOut) {
-  WebApplicationInfo web_application_info;
-  web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
-
-  // Not registering a service worker means we'll wait and time out for the
-  // worker.
-  SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest());
-  SetShouldManifestTimeOut(false);
-  SetShouldImageTimeOut(false);
-
-  ObserverWaiter waiter;
-  std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
-  fetcher->OnDidGetWebApplicationInfo(web_application_info);
-  waiter.WaitForDataAvailable();
-
-  EXPECT_EQ(check_webapk_compatibility(),
-            waiter.determined_webapk_compatibility());
-  EXPECT_FALSE(waiter.is_webapk_compatible());
-  EXPECT_TRUE(waiter.title_available());
-  EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName));
-  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().user_title,
-                                kDefaultManifestShortName));
+  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
+                                kWebApplicationInfoTitle));
+  EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
+  EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
+            GURL(kDefaultIconUrl));
 }
 
 INSTANTIATE_TEST_CASE_P(CheckWebApkCompatibility,
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 aaa36496..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/browsing_data/browsing_data_appcache_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_appcache_helper_unittest.cc
index f6263502f..7b89c894 100644
--- a/chrome/browser/browsing_data/browsing_data_appcache_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_appcache_helper_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind_helpers.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
+#include "build/build_config.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
@@ -123,7 +124,14 @@
   ASSERT_TRUE(helper->empty());
 }
 
-TEST_F(CannedBrowsingDataAppCacheHelperTest, Delete) {
+// Flaky on linux. See crbug.com/740801.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#define MAYBE_Delete DISABLED_Delete
+#else
+#define MAYBE_Delete Delete
+#endif
+
+TEST_F(CannedBrowsingDataAppCacheHelperTest, MAYBE_Delete) {
   GURL manifest1("http://example.com/manifest1.xml");
   GURL manifest2("http://foo.example.com/manifest2.xml");
   GURL manifest3("http://bar.example.com/manifest3.xml");
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/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 00a4d7d..b08ed14 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -310,6 +310,8 @@
     "arc/auth/arc_auth_context.h",
     "arc/auth/arc_auth_service.cc",
     "arc/auth/arc_auth_service.h",
+    "arc/auth/arc_auth_service_factory.cc",
+    "arc/auth/arc_auth_service_factory.h",
     "arc/auth/arc_background_auth_code_fetcher.cc",
     "arc/auth/arc_background_auth_code_fetcher.h",
     "arc/auth/arc_fetcher_base.h",
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index d3de137..2c72c4d 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
+#include "chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h"
 #include "chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
 #include "chrome/browser/chromeos/arc/downloads_watcher/arc_downloads_watcher_service.h"
 #include "chrome/browser/chromeos/arc/enterprise/arc_enterprise_reporting_service.h"
@@ -97,8 +97,6 @@
   arc_service_manager_->AddService(
       base::MakeUnique<ArcAudioBridge>(arc_bridge_service));
   arc_service_manager_->AddService(
-      base::MakeUnique<ArcAuthService>(arc_bridge_service));
-  arc_service_manager_->AddService(
       base::MakeUnique<ArcBluetoothBridge>(arc_bridge_service));
   arc_service_manager_->AddService(
       base::MakeUnique<ArcBootErrorNotification>(arc_bridge_service));
@@ -200,6 +198,7 @@
   // to be running at the beginning of the container run.
   // List in lexicographical order.
   ArcAccessibilityHelperBridgeFactory::GetForBrowserContext(profile);
+  ArcAuthServiceFactory::GetForBrowserContext(profile);
 
   arc_service_manager_->AddService(base::MakeUnique<ArcBootPhaseMonitorBridge>(
       arc_service_manager_->arc_bridge_service(),
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
index c62c54d..be4bc340 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -16,12 +16,13 @@
 #include "chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_features.h"
+#include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
@@ -134,18 +135,27 @@
   const AccountInfoCallback account_info_callback_;
 };
 
-ArcAuthService::ArcAuthService(ArcBridgeService* bridge_service)
-    : ArcService(bridge_service), binding_(this), weak_ptr_factory_(this) {
-  arc_bridge_service()->auth()->AddObserver(this);
+ArcAuthService::ArcAuthService(Profile* profile,
+                               ArcBridgeService* arc_bridge_service)
+    : profile_(profile),
+      arc_bridge_service_(arc_bridge_service),
+      binding_(this),
+      weak_ptr_factory_(this) {
+  arc_bridge_service_->auth()->AddObserver(this);
 }
 
 ArcAuthService::~ArcAuthService() {
-  arc_bridge_service()->auth()->RemoveObserver(this);
+  // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and
+  // BrowserContextKeyedService is not nested.
+  // If ArcServiceManager::Get() returns nullptr, it is already destructed,
+  // so do not touch it.
+  if (ArcServiceManager::Get())
+    arc_bridge_service_->auth()->RemoveObserver(this);
 }
 
 void ArcAuthService::OnInstanceReady() {
   auto* instance =
-      ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->auth(), Init);
+      ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(), Init);
   DCHECK(instance);
   mojom::AuthHostPtr host_proxy;
   binding_.Bind(mojo::MakeRequest(&host_proxy));
@@ -205,7 +215,7 @@
 
 void ArcAuthService::OnAccountInfoReady(mojom::AccountInfoPtr account_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->auth(),
+  auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
                                                OnAccountInfoReady);
   DCHECK(instance);
   instance->OnAccountInfoReady(std::move(account_info));
@@ -235,8 +245,7 @@
 void ArcAuthService::GetIsAccountManagedDeprecated(
     const GetIsAccountManagedDeprecatedCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  callback.Run(
-      policy_util::IsAccountManaged(ArcSessionManager::Get()->profile()));
+  callback.Run(policy_util::IsAccountManaged(profile_));
 }
 
 void ArcAuthService::RequestAccountInfoInternal(
@@ -247,18 +256,16 @@
   DCHECK(!fetcher_);
 
   if (IsArcOptInVerificationDisabled()) {
-    notifier->Notify(
-        false /* = is_enforced */, std::string() /* auth_info */,
-        std::string() /* auth_name */, GetAccountType(),
-        policy_util::IsAccountManaged(ArcSessionManager::Get()->profile()));
+    notifier->Notify(false /* = is_enforced */, std::string() /* auth_info */,
+                     std::string() /* auth_name */, GetAccountType(),
+                     policy_util::IsAccountManaged(profile_));
     return;
   }
 
   // Hereafter asynchronous operation. Remember the notifier.
   notifier_ = std::move(notifier);
 
-  Profile* profile = ArcSessionManager::Get()->profile();
-  if (profile && IsActiveDirectoryUserForProfile(profile)) {
+  if (IsActiveDirectoryUserForProfile(profile_)) {
     // For Active Directory enrolled devices, we get an enrollment token for a
     // managed Google Play account from DMServer.
     auto enrollment_token_fetcher =
@@ -276,9 +283,8 @@
     auth_code_fetcher = base::MakeUnique<ArcRobotAuthCodeFetcher>();
   } else if (base::FeatureList::IsEnabled(arc::kArcUseAuthEndpointFeature)) {
     // Optionally retrieve auth code in silent mode.
-    DCHECK(profile);
     auth_code_fetcher = base::MakeUnique<ArcBackgroundAuthCodeFetcher>(
-        profile, ArcSessionManager::Get()->auth_context());
+        profile_, ArcSessionManager::Get()->auth_context());
   } else {
     // Report that silent auth code is not activated. All other states are
     // reported in ArcBackgroundAuthCodeFetcher.
@@ -306,13 +312,8 @@
   switch (status) {
     case ArcActiveDirectoryEnrollmentTokenFetcher::Status::SUCCESS: {
       // Save user_id to the user profile.
-      Profile* const profile = ArcSessionManager::Get()->profile();
-      if (!profile) {
-        LOG(ERROR) << "Profile is not available.";
-      } else {
-        profile->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId,
-                                       user_id);
-      }
+      profile_->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId,
+                                      user_id);
 
       // Send enrollment token to arc.
       notifier_->Notify(true /*is_enforced*/, enrollment_token,
@@ -346,11 +347,9 @@
     return;
   }
 
-  notifier_->Notify(
-      !IsArcOptInVerificationDisabled(), auth_code,
-      ArcSessionManager::Get()->auth_context()->full_account_id(),
-      GetAccountType(),
-      policy_util::IsAccountManaged(ArcSessionManager::Get()->profile()));
+  notifier_->Notify(!IsArcOptInVerificationDisabled(), auth_code,
+                    ArcSessionManager::Get()->auth_context()->full_account_id(),
+                    GetAccountType(), policy_util::IsAccountManaged(profile_));
   notifier_.reset();
 }
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.h b/chrome/browser/chromeos/arc/auth/arc_auth_service.h
index 7e58423..42d8ffea 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.h
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.h
@@ -11,21 +11,24 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
-#include "components/arc/arc_service.h"
 #include "components/arc/common/auth.mojom.h"
 #include "components/arc/instance_holder.h"
+#include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+class Profile;
+
 namespace arc {
 
 class ArcFetcherBase;
+class ArcBridgeService;
 
 // Implementation of ARC authorization.
-class ArcAuthService : public ArcService,
+class ArcAuthService : public KeyedService,
                        public mojom::AuthHost,
                        public InstanceHolder<mojom::AuthInstance>::Observer {
  public:
-  explicit ArcAuthService(ArcBridgeService* bridge_service);
+  ArcAuthService(Profile* profile, ArcBridgeService* bridge_service);
   ~ArcAuthService() override;
 
   // For supporting ArcServiceManager::GetService<T>().
@@ -72,6 +75,9 @@
   // Called to let ARC container know the account info.
   void OnAccountInfoReady(mojom::AccountInfoPtr account_info);
 
+  Profile* const profile_;
+  ArcBridgeService* const arc_bridge_service_;
+
   mojo::Binding<mojom::AuthHost> binding_;
 
   std::unique_ptr<AccountInfoNotifier> notifier_;
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index cd420e6..b38b65d5 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_context.h"
 #include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
+#include "chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h"
 #include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
@@ -198,7 +199,7 @@
 
   FakeAuthInstance auth_instance;
   ArcAuthService* auth_service =
-      ArcServiceManager::GetGlobalService<ArcAuthService>();
+      ArcAuthServiceFactory::GetForBrowserContext(profile());
   ASSERT_TRUE(auth_service);
 
   ArcBridgeService* arc_bridge_service =
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.cc
new file mode 100644
index 0000000..20f766e
--- /dev/null
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.cc
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace arc {
+
+ArcAuthService* ArcAuthServiceFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<ArcAuthService*>(
+      GetInstance()->GetServiceForBrowserContext(context, true /* create */));
+}
+
+// static
+ArcAuthServiceFactory* ArcAuthServiceFactory::GetInstance() {
+  return base::Singleton<ArcAuthServiceFactory>::get();
+}
+
+ArcAuthServiceFactory::ArcAuthServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "ArcAuthServiceFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+ArcAuthServiceFactory::~ArcAuthServiceFactory() = default;
+
+KeyedService* ArcAuthServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  auto* arc_service_manager = arc::ArcServiceManager::Get();
+
+  // Practically, this is in testing case.
+  if (!arc_service_manager) {
+    VLOG(2) << "ArcServiceManager is not available.";
+    return nullptr;
+  }
+
+  if (arc_service_manager->browser_context() != context) {
+    VLOG(2) << "Non ARC allowed browser context.";
+    return nullptr;
+  }
+
+  return new ArcAuthService(Profile::FromBrowserContext(context),
+                            arc_service_manager->arc_bridge_service());
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h b/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h
new file mode 100644
index 0000000..d7d5c8e
--- /dev/null
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_factory.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace arc {
+
+class ArcAuthService;
+
+// Factory for ArcAuthService.
+class ArcAuthServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns the ArcAuthService for the given |context|,
+  // or nullptr if |context| is not allowed to use ARC.
+  // If the instance is not yet createad, this creates a new service instance.
+  static ArcAuthService* GetForBrowserContext(content::BrowserContext* context);
+
+  // Returns the factory instance.
+  static ArcAuthServiceFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<ArcAuthServiceFactory>;
+
+  ArcAuthServiceFactory();
+  ~ArcAuthServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory overrides:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAuthServiceFactory);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_FACTORY_H_
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/policy/user_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
index ca3786cb..d5b195b 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
@@ -20,7 +19,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chromeos/dbus/mock_cryptohome_client.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
 #include "chromeos/dbus/mock_session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
@@ -38,7 +37,6 @@
     chromeos::SessionManagerClient::RetrievePolicyResponseType;
 
 using testing::AllOf;
-using testing::AnyNumber;
 using testing::Eq;
 using testing::Mock;
 using testing::Property;
@@ -51,15 +49,8 @@
 
 namespace {
 
-const char kSanitizedUsername[] =
-    "0123456789ABCDEF0123456789ABCDEF012345678@example.com";
 const char kDefaultHomepage[] = "http://chromium.org";
 
-ACTION_P2(SendSanitizedUsername, call_status, sanitized_username) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(arg1, call_status, sanitized_username));
-}
-
 class UserCloudPolicyStoreChromeOSTest : public testing::Test {
  protected:
   UserCloudPolicyStoreChromeOSTest()
@@ -67,11 +58,6 @@
             base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
 
   void SetUp() override {
-    EXPECT_CALL(cryptohome_client_, GetSanitizedUsername(cryptohome_id_, _))
-        .Times(AnyNumber())
-        .WillRepeatedly(SendSanitizedUsername(
-            chromeos::DBUS_METHOD_CALL_SUCCESS, kSanitizedUsername));
-
     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
     store_.reset(new UserCloudPolicyStoreChromeOS(
         &cryptohome_client_, &session_manager_client_,
@@ -83,7 +69,7 @@
     // the stored/loaded policy blob succeeds.
     std::string public_key = policy_.GetPublicSigningKeyAsString();
     ASSERT_FALSE(public_key.empty());
-    StoreUserPolicyKey(public_key);
+    ASSERT_NO_FATAL_FAILURE(StoreUserPolicyKey(public_key));
 
     policy_.payload().mutable_homepagelocation()->set_value(kDefaultHomepage);
     policy_.Build();
@@ -211,12 +197,15 @@
   }
 
   base::FilePath user_policy_key_file() {
-    return user_policy_dir().AppendASCII(kSanitizedUsername)
-                            .AppendASCII("policy.pub");
+    const std::string sanitized_username =
+        chromeos::CryptohomeClient::GetStubSanitizedUsername(cryptohome_id_);
+    return user_policy_dir()
+        .AppendASCII(sanitized_username)
+        .AppendASCII("policy.pub");
   }
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  chromeos::MockCryptohomeClient cryptohome_client_;
+  chromeos::FakeCryptohomeClient cryptohome_client_;
   chromeos::MockSessionManagerClient session_manager_client_;
   UserPolicyBuilder policy_;
   MockCloudPolicyStoreObserver observer_;
@@ -369,11 +358,7 @@
 
 TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithoutPolicyKey) {
   // Make the dbus call to cryptohome fail.
-  Mock::VerifyAndClearExpectations(&cryptohome_client_);
-  EXPECT_CALL(cryptohome_client_, GetSanitizedUsername(cryptohome_id_, _))
-      .Times(AnyNumber())
-      .WillRepeatedly(SendSanitizedUsername(chromeos::DBUS_METHOD_CALL_FAILURE,
-                                            std::string()));
+  cryptohome_client_.SetServiceIsAvailable(false);
 
   // Store policy.
   chromeos::SessionManagerClient::StorePolicyCallback store_callback;
@@ -503,8 +488,6 @@
               BlockingRetrievePolicyForUser(cryptohome_id_, _))
       .WillOnce(DoAll(SetArgPointee<1>(policy_.GetBlob()),
                       Return(RetrievePolicyResponseType::SUCCESS)));
-  EXPECT_CALL(cryptohome_client_, BlockingGetSanitizedUsername(cryptohome_id_))
-      .WillOnce(Return(kSanitizedUsername));
 
   EXPECT_FALSE(store_->policy());
   store_->LoadImmediately();
@@ -513,7 +496,6 @@
   // must be done within the test.
   Mock::VerifyAndClearExpectations(&observer_);
   Mock::VerifyAndClearExpectations(&session_manager_client_);
-  Mock::VerifyAndClearExpectations(&cryptohome_client_);
 
   // The policy should become available without having to spin any loops.
   ASSERT_TRUE(store_->policy());
@@ -567,14 +549,14 @@
               BlockingRetrievePolicyForUser(cryptohome_id_, _))
       .WillOnce(DoAll(SetArgPointee<1>(policy_.GetBlob()),
                       Return(RetrievePolicyResponseType::SUCCESS)));
-  EXPECT_CALL(cryptohome_client_, BlockingGetSanitizedUsername(cryptohome_id_))
-      .WillOnce(Return(""));
+
+  // Make the dbus call to cryptohome fail.
+  cryptohome_client_.SetServiceIsAvailable(false);
 
   EXPECT_FALSE(store_->policy());
   store_->LoadImmediately();
   Mock::VerifyAndClearExpectations(&observer_);
   Mock::VerifyAndClearExpectations(&session_manager_client_);
-  Mock::VerifyAndClearExpectations(&cryptohome_client_);
 
   EXPECT_FALSE(store_->policy());
   EXPECT_TRUE(store_->policy_map().empty());
@@ -588,14 +570,13 @@
               BlockingRetrievePolicyForUser(cryptohome_id_, _))
       .WillOnce(DoAll(SetArgPointee<1>(policy_.GetBlob()),
                       Return(RetrievePolicyResponseType::SUCCESS)));
-  EXPECT_CALL(cryptohome_client_, BlockingGetSanitizedUsername(cryptohome_id_))
-      .WillOnce(Return("wrong@example.com"));
+  // Ensure no policy data.
+  ASSERT_TRUE(base::DeleteFile(user_policy_key_file(), false));
 
   EXPECT_FALSE(store_->policy());
   store_->LoadImmediately();
   Mock::VerifyAndClearExpectations(&observer_);
   Mock::VerifyAndClearExpectations(&session_manager_client_);
-  Mock::VerifyAndClearExpectations(&cryptohome_client_);
 
   EXPECT_FALSE(store_->policy());
   EXPECT_TRUE(store_->policy_map().empty());
diff --git a/chrome/browser/chromeos/power/cpu_data_collector.cc b/chrome/browser/chromeos/power/cpu_data_collector.cc
index 189b192..8ed28c2 100644
--- a/chrome/browser/chromeos/power/cpu_data_collector.cc
+++ b/chrome/browser/chromeos/power/cpu_data_collector.cc
@@ -203,17 +203,19 @@
     std::vector<std::string>* cpu_freq_state_names,
     std::vector<CpuDataCollector::StateOccupancySample>* freq_samples) {
   base::Time start_time = base::Time::Now();
+  int online_cpu_count = 0;
   for (int cpu = 0; cpu < cpu_count; ++cpu) {
     CpuDataCollector::StateOccupancySample freq_sample;
     freq_sample.time_in_state.reserve(cpu_freq_state_names->size());
     freq_sample.time = base::Time::Now();
     freq_sample.cpu_online = CpuIsOnline(cpu);
+    online_cpu_count += (freq_sample.cpu_online ? 1 : 0);
     freq_samples->push_back(freq_sample);
   }
 
   if (base::PathExists(base::FilePath(kCpuFreqAllTimeInStatePath))) {
     if (!CpuDataCollector::ReadCpuFreqAllTimeInState(
-            cpu_count, base::FilePath(kCpuFreqAllTimeInStatePath),
+            online_cpu_count, base::FilePath(kCpuFreqAllTimeInStatePath),
             cpu_freq_state_names, freq_samples)) {
       freq_samples->clear();
       return;
@@ -353,7 +355,7 @@
 }
 
 bool CpuDataCollector::ReadCpuFreqAllTimeInState(
-    int cpu_count,
+    int online_cpu_count,
     const base::FilePath& path,
     std::vector<std::string>* cpu_freq_state_names,
     std::vector<CpuDataCollector::StateOccupancySample>* freq_samples) {
@@ -382,7 +384,7 @@
         base::SplitStringPiece(lines[line_num], "\t", base::TRIM_WHITESPACE,
                                base::SPLIT_WANT_NONEMPTY);
     int freq_in_khz;
-    if (array.size() != static_cast<size_t>(cpu_count) + 1 ||
+    if (array.size() != static_cast<size_t>(online_cpu_count) + 1 ||
         !base::StringToInt(array[0], &freq_in_khz)) {
       LOG(ERROR) << "Bad format at \"" << lines[line_num] << "\" in "
                  << path.value() << ". Dropping sample.";
@@ -391,11 +393,11 @@
 
     const std::string state_name = base::IntToString(freq_in_khz / 1000);
     size_t index = EnsureInVector(state_name, cpu_freq_state_names);
-    for (int cpu = 0; cpu < cpu_count; ++cpu) {
-      // array.size() is previously checked to be equal to cpu_count+1. cpu
-      // ranges from [0,cpu_count), so cpu+1 never exceeds cpu_count and is
-      // safe.
-      if (!(*freq_samples)[cpu].cpu_online || array[cpu + 1] == "N/A") {
+    for (int cpu = 0; cpu < online_cpu_count; ++cpu) {
+      // array.size() is previously checked to be equal to online_cpu_count+1.
+      // cpu ranges from [0,online_cpu_count), so cpu+1 never exceeds
+      // online_cpu_count and is safe.
+      if (array[cpu + 1] == "N/A") {
         continue;
       }
       if (index >= (*freq_samples)[cpu].time_in_state.size())
diff --git a/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc b/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
index bb8a3689..bdbcc2d 100644
--- a/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
+++ b/chrome/browser/chromeos/power/cpu_data_collector_unittest.cc
@@ -16,42 +16,50 @@
 namespace chromeos {
 namespace {
 
-// The suffix path of fake cpu frequency file for cpu0.
+// The suffix path of fake CPU frequency file for cpu0.
 constexpr char kTimeInStateSuffixPathCpu0[] = "cpu0/time_in_state";
 
-// The suffix path of fake cpu frequency file for cpu1.
+// The suffix path of fake CPU frequency file for cpu1.
 constexpr char kTimeInStateSuffixPathCpu1[] = "cpu1/time_in_state";
 
-// The suffix path of fake cpu frequency file for all cpus.
+// The suffix path of fake CPU frequency file for all cpus.
 constexpr char kAllTimeInStateSuffixPath[] = "all_time_in_state";
 
-// The string content of the fake cpu frequency file for cpu0.
+// The string content of the fake CPU frequency file for cpu0.
 constexpr char kTimeInStateContentCpu0[] =
     "20000 30000000\n"
     "60000 90000\n"
     "100000 50000\n";
 
-// The string content of the fake cpu frequency file for cpu1.
+// The string content of the fake CPU frequency file for cpu1.
 constexpr char kTimeInStateContentCpu1[] =
     "20000 31000000\n"
     "60000 91000\n"
     "100000 51000\n";
 
-// The string content of the fake cpu frequency file for all cpus.
+// The string content of the fake CPU frequency file for all CPUs.
 constexpr char kAllTimeInStateContent[] =
     "freq\t\tcpu0\t\tcpu1\t\t\n"
     "20000\t\t30000000\t\t31000000\t\t\n"
     "60000\t\t90000\t\t91000\t\t\n"
     "100000\t\t50000\t\t51000\t\t\n";
 
-// The string content of the fake cpu frequency file for all cpus except one
-// that reports "N/A" as the cpu/freq combinations that are invalid.
+// The string content of the fake CPU frequency file for all CPUs except one
+// that reports "N/A" as the CPU/freq combinations that are invalid.
 constexpr char kAllTimeInStateContentNA[] =
     "freq\t\tcpu0\t\tcpu1\t\tcpu2\t\t\n"
     "20000\t\t30000000\t\t31000000\t\tN/A\t\t\n"
     "60000\t\t90000\t\t91000\t\tN/A\t\t\n"
     "100000\t\t50000\t\t51000\t\tN/A\t\t\n";
 
+// The string content of the fake CPU frequency file for all CPUs except one
+// that does not report freq as the CPU is turned off.
+constexpr char kAllTimeInStateContentOff[] =
+    "freq\t\tcpu0\t\tcpu1\t\tcpu2\t\t\n"
+    "20000\t\t30000000\t\t31000000\t\t\n"
+    "60000\t\t90000\t\t91000\t\t\n"
+    "100000\t\t50000\t\t51000\t\t\n";
+
 }  // namespace
 
 class CpuDataCollectorTest : public testing::Test {
@@ -78,7 +86,7 @@
   }
 
  protected:
-  // Expected cpu frequency state names after calling |ReadCpuFreqTimeInState|
+  // Expected CPU frequency state names after calling |ReadCpuFreqTimeInState|
   // or |ReadCpuFreqAllTimeInState|
   const std::vector<std::string> kExpectedCpuFreqStateNames;
 
@@ -133,7 +141,7 @@
   std::vector<CpuDataCollector::StateOccupancySample> freq_samples;
   CpuDataCollector::StateOccupancySample freq_sample_cpu0;
   CpuDataCollector::StateOccupancySample freq_sample_cpu1;
-  // |ReadCpuFreqAllTimeInState| only completes sample for cpu that is online.
+  // |ReadCpuFreqAllTimeInState| only collects samples for CPUs that are online.
   freq_sample_cpu0.cpu_online = true;
   freq_sample_cpu1.cpu_online = true;
   freq_samples.push_back(freq_sample_cpu0);
@@ -157,7 +165,7 @@
   CpuDataCollector::StateOccupancySample freq_sample_cpu0;
   CpuDataCollector::StateOccupancySample freq_sample_cpu1;
   CpuDataCollector::StateOccupancySample freq_sample_cpu2;
-  // |ReadCpuFreqAllTimeInState| only completes sample for cpu that is online.
+  // |ReadCpuFreqAllTimeInState| only collects samples for CPUs that are online.
   freq_sample_cpu0.cpu_online = true;
   freq_sample_cpu1.cpu_online = true;
   freq_sample_cpu2.cpu_online = true;
@@ -173,4 +181,31 @@
   EXPECT_TRUE(freq_samples[2].time_in_state.empty());
 }
 
+TEST_F(CpuDataCollectorTest, ReadCpuFreqAllTimeInStateOff) {
+  ASSERT_TRUE(base::CreateTemporaryFile(&all_time_in_state_path_));
+  ASSERT_TRUE(base::WriteFile(
+                  all_time_in_state_path_, kAllTimeInStateContentOff,
+                  static_cast<int>(strlen(kAllTimeInStateContentOff))) != -1);
+
+  std::vector<std::string> cpu_freq_state_names;
+  std::vector<CpuDataCollector::StateOccupancySample> freq_samples;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu0;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu1;
+  CpuDataCollector::StateOccupancySample freq_sample_cpu2;
+  // |ReadCpuFreqAllTimeInState| only collects samples for CPUs that are online.
+  freq_sample_cpu0.cpu_online = true;
+  freq_sample_cpu1.cpu_online = true;
+  freq_sample_cpu2.cpu_online = false;
+  freq_samples.push_back(freq_sample_cpu0);
+  freq_samples.push_back(freq_sample_cpu1);
+  freq_samples.push_back(freq_sample_cpu2);
+
+  CpuDataCollector::ReadCpuFreqAllTimeInState(
+      2, all_time_in_state_path_, &cpu_freq_state_names, &freq_samples);
+  EXPECT_EQ(kExpectedCpuFreqStateNames, cpu_freq_state_names);
+  EXPECT_EQ(kExpectedTimeInStateCpu0, freq_samples[0].time_in_state);
+  EXPECT_EQ(kExpectedTimeInStateCpu1, freq_samples[1].time_in_state);
+  EXPECT_TRUE(freq_samples[2].time_in_state.empty());
+}
+
 }  // namespace chromeos
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/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 623dabe..b3d8c67 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -1000,6 +1000,9 @@
       "//ui/file_manager",
       "//ui/views/",
     ]
+    if (enable_nacl) {
+      deps += [ "//chrome/browser/resources/chromeos/zip_archiver" ]
+    }
   } else {
     sources += [
       "api/easy_unlock_private/easy_unlock_private_crypto_delegate_stub.cc",
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/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
index ad24c83..f93958a 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -36,9 +36,6 @@
     {"webstore_widget/app/icons/icon_16.png", IDR_WEBSTORE_ICON_16},
     {"webstore_widget/app/icons/icon_32.png", IDR_WEBSTORE_ICON_32},
     {"webstore_widget/app/icons/icon_128.png", IDR_WEBSTORE_ICON},
-#ifndef DISABLE_NACL
-    {"zip_archiver/zip_archiver_pnacl.pexe.js", IDR_ZIP_ARCHIVER_PEXE},
-#endif
 #endif
   };
 
diff --git a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
index 4568f74..0de41d2 100644
--- a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
+++ b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
@@ -40,6 +40,7 @@
     extension_misc::kSpeechSynthesisExtensionId,
     extension_misc::kSwitchAccessExtensionId,
     extension_misc::kZIPUnpackerExtensionId,
+    extension_misc::kZipArchiverExtensionId,
 #endif
   };
 
@@ -110,7 +111,6 @@
     case IDR_FILEMANAGER_MANIFEST:
     case IDR_FIRST_RUN_DIALOG_MANIFEST:
     case IDR_GALLERY_MANIFEST:
-    case IDR_ZIP_ARCHIVER_MANIFEST:
     case IDR_KEYBOARD_MANIFEST:
     case IDR_MOBILE_MANIFEST:
     case IDR_VIDEO_PLAYER_MANIFEST:
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index b5907e94..86b03045 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -319,10 +319,13 @@
 
 void ComponentLoader::AddZipArchiverExtension() {
 #if defined(OS_CHROMEOS)
+  base::FilePath resources_path;
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-      chromeos::switches::kEnableZipArchiverOnFileManager)) {
-    Add(IDR_ZIP_ARCHIVER_MANIFEST,
-        base::FilePath(FILE_PATH_LITERAL("zip_archiver")));
+          chromeos::switches::kEnableZipArchiverOnFileManager) &&
+      PathService::Get(chrome::DIR_RESOURCES, &resources_path)) {
+    AddComponentFromDir(
+        resources_path.Append(extension_misc::kZipArchiverExtensionPath),
+        extension_misc::kZipArchiverExtensionId, base::Closure());
   }
 #endif  // defined(OS_CHROMEOS)
 }
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 672ffc3..525a739d 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 "
@@ -1436,6 +1431,12 @@
     "set, Chrome will forget the launcher has been installed each time it "
     "starts. This is used for testing the App Launcher install flow.";
 
+const char kResourceLoadSchedulerName[] = "Use the resource load scheduler";
+
+const char kResourceLoadSchedulerDescription[] =
+    "Uses the resource load scheduler in blink to schedule and throttle "
+    "resource load requests.";
+
 #if defined(OS_CHROMEOS)
 
 const char kFirstRunUiTransitionsName[] =
@@ -3146,4 +3147,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..515b506 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[];
@@ -606,6 +603,9 @@
 extern const char kResetAppListInstallStateName[];
 extern const char kResetAppListInstallStateDescription[];
 
+extern const char kResourceLoadSchedulerName[];
+extern const char kResourceLoadSchedulerDescription[];
+
 extern const char kRunAllFlashInAllowModeName[];
 extern const char kRunAllFlashInAllowModeDescription[];
 
@@ -1114,6 +1114,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/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc
index dfd105b..ba07cb8f6 100644
--- a/chrome/browser/installable/installable_manager.cc
+++ b/chrome/browser/installable/installable_manager.cc
@@ -69,40 +69,15 @@
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InstallableManager);
 
-struct InstallableManager::ManifestProperty {
-  InstallableStatusCode error = NO_ERROR_DETECTED;
-  GURL url;
-  content::Manifest manifest;
-  bool fetched = false;
-};
+InstallableManager::IconProperty::IconProperty()
+    : error(NO_ERROR_DETECTED), url(), icon(), fetched(false) {}
 
-struct InstallableManager::ValidManifestProperty {
-  InstallableStatusCode error = NO_ERROR_DETECTED;
-  bool is_valid = false;
-  bool fetched = false;
-};
+InstallableManager::IconProperty::IconProperty(IconProperty&& other) = default;
 
-struct InstallableManager::ServiceWorkerProperty {
-  InstallableStatusCode error = NO_ERROR_DETECTED;
-  bool has_worker = false;
-  bool fetched = false;
-};
+InstallableManager::IconProperty::~IconProperty() {}
 
-struct InstallableManager::IconProperty {
-  IconProperty() :
-    error(NO_ERROR_DETECTED), url(), icon(), fetched(false) { }
-  IconProperty(IconProperty&& other) = default;
-  IconProperty& operator=(IconProperty&& other) = default;
-
-  InstallableStatusCode error = NO_ERROR_DETECTED;
-  GURL url;
-  std::unique_ptr<SkBitmap> icon;
-  bool fetched;
-
- private:
-  // This class contains a std::unique_ptr and therefore must be move-only.
-  DISALLOW_COPY_AND_ASSIGN(IconProperty);
-};
+InstallableManager::IconProperty& InstallableManager::IconProperty::operator=(
+    InstallableManager::IconProperty&& other) = default;
 
 InstallableManager::InstallableManager(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
diff --git a/chrome/browser/installable/installable_manager.h b/chrome/browser/installable/installable_manager.h
index 0a1c51c..42b01761 100644
--- a/chrome/browser/installable/installable_manager.h
+++ b/chrome/browser/installable/installable_manager.h
@@ -137,8 +137,8 @@
   // at all if a service worker is never registered).
   //
   // Calls requesting data that is already fetched will return the cached data.
-  void GetData(const InstallableParams& params,
-               const InstallableCallback& callback);
+  virtual void GetData(const InstallableParams& params,
+                       const InstallableCallback& callback);
 
   // Called via AppBannerManagerAndroid to record metrics on how often the
   // installable check is completed when the menu or add to homescreen menu item
@@ -153,8 +153,10 @@
   virtual void OnWaitingForServiceWorker() {}
 
  private:
+  friend class AddToHomescreenDataFetcherTest;
   friend class InstallableManagerBrowserTest;
   friend class InstallableManagerUnitTest;
+  friend class TestInstallableManager;
   FRIEND_TEST_ALL_PREFIXES(InstallableManagerBrowserTest,
                            ManagerBeginsInEmptyState);
   FRIEND_TEST_ALL_PREFIXES(InstallableManagerBrowserTest, CheckWebapp);
@@ -166,10 +168,41 @@
   using Task = std::pair<InstallableParams, InstallableCallback>;
   using IconParams = std::tuple<int, int, content::Manifest::Icon::IconPurpose>;
 
-  struct ManifestProperty;
-  struct ValidManifestProperty;
-  struct ServiceWorkerProperty;
-  struct IconProperty;
+  struct ManifestProperty {
+    InstallableStatusCode error = NO_ERROR_DETECTED;
+    GURL url;
+    content::Manifest manifest;
+    bool fetched = false;
+  };
+
+  struct ValidManifestProperty {
+    InstallableStatusCode error = NO_ERROR_DETECTED;
+    bool is_valid = false;
+    bool fetched = false;
+  };
+
+  struct ServiceWorkerProperty {
+    InstallableStatusCode error = NO_ERROR_DETECTED;
+    bool has_worker = false;
+    bool is_waiting = false;
+    bool fetched = false;
+  };
+
+  struct IconProperty {
+    IconProperty();
+    IconProperty(IconProperty&& other);
+    ~IconProperty();
+    IconProperty& operator=(IconProperty&& other);
+
+    InstallableStatusCode error;
+    GURL url;
+    std::unique_ptr<SkBitmap> icon;
+    bool fetched;
+
+   private:
+    // This class contains a std::unique_ptr and therefore must be move-only.
+    DISALLOW_COPY_AND_ASSIGN(IconProperty);
+  };
 
   // Returns an IconParams object that queries for a primary icon conforming to
   // the primary icon size parameters in |params|.
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 8b64aa7..4d7bb356 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/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc
index 8e90abe..3c32dcb 100644
--- a/chrome/browser/media/media_engagement_contents_observer.cc
+++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -8,8 +8,12 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 
-constexpr base::TimeDelta
-    MediaEngagementContentsObserver::kSignificantMediaPlaybackTime;
+namespace {
+
+constexpr base::TimeDelta kSignificantMediaPlaybackTime =
+    base::TimeDelta::FromSeconds(7);
+
+}  // namespace.
 
 // This is the minimum size (in px) of each dimension that a media
 // element has to be in order to be determined significant.
@@ -86,8 +90,6 @@
 void MediaEngagementContentsObserver::MediaStartedPlaying(
     const MediaPlayerInfo& media_player_info,
     const MediaPlayerId& media_player_id) {
-  // TODO(mlamouri): check if:
-  // - the playback has the minimum size requirements;
   if (!media_player_info.has_audio)
     return;
 
@@ -96,12 +98,12 @@
   UpdateTimer();
 }
 
-void MediaEngagementContentsObserver::MediaMutedStateChanged(
+void MediaEngagementContentsObserver::MediaMutedStatusChanged(
     const MediaPlayerId& id,
-    bool muted_state) {
-  GetPlayerState(id)->muted = muted_state;
+    bool muted) {
+  GetPlayerState(id)->muted = muted;
 
-  if (muted_state)
+  if (muted)
     MaybeRemoveSignificantPlayer(id);
   else
     MaybeInsertSignificantPlayer(id);
@@ -143,6 +145,11 @@
 void MediaEngagementContentsObserver::OnSignificantMediaPlaybackTime() {
   DCHECK(!significant_playback_recorded_);
 
+  // Do not record significant playback if the tab did not make
+  // a sound in the last two seconds.
+  if (!web_contents()->WasRecentlyAudible())
+    return;
+
   significant_playback_recorded_ = true;
 
   if (committed_origin_.unique())
@@ -183,6 +190,7 @@
   if (AreConditionsMet()) {
     if (playback_timer_->IsRunning())
       return;
+
     playback_timer_->Start(
         FROM_HERE, kSignificantMediaPlaybackTime,
         base::Bind(
diff --git a/chrome/browser/media/media_engagement_contents_observer.h b/chrome/browser/media/media_engagement_contents_observer.h
index be7fb6a..0e2356cf 100644
--- a/chrome/browser/media/media_engagement_contents_observer.h
+++ b/chrome/browser/media/media_engagement_contents_observer.h
@@ -29,7 +29,7 @@
   void MediaStoppedPlaying(const MediaPlayerInfo& media_player_info,
                            const MediaPlayerId& media_player_id) override;
   void DidUpdateAudioMutingState(bool muted) override;
-  void MediaMutedStateChanged(const MediaPlayerId& id, bool muted_state);
+  void MediaMutedStatusChanged(const MediaPlayerId& id, bool muted) override;
   void MediaResized(const gfx::Size& size, const MediaPlayerId& id) override;
 
   static const int kSignificantSize;
@@ -39,9 +39,6 @@
   friend MediaEngagementService;
   friend MediaEngagementContentsObserverTest;
 
-  static constexpr base::TimeDelta kSignificantMediaPlaybackTime =
-      base::TimeDelta::FromSeconds(7);
-
   MediaEngagementContentsObserver(content::WebContents* web_contents,
                                   MediaEngagementService* service);
 
diff --git a/chrome/browser/media/media_engagement_contents_observer_unittest.cc b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
index 7cc4d225..7a509d11 100644
--- a/chrome/browser/media/media_engagement_contents_observer_unittest.cc
+++ b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class MediaEngagementContentsObserverTest
@@ -22,6 +23,8 @@
     scoped_feature_list_.InitFromCommandLine("media-engagement", std::string());
 
     ChromeRenderViewHostTestHarness::SetUp();
+    SetContents(content::WebContentsTester::CreateTestWebContents(
+        browser_context(), nullptr));
 
     MediaEngagementService* service = MediaEngagementService::Get(profile());
     ASSERT_TRUE(service);
@@ -31,7 +34,7 @@
     playback_timer_ = new base::MockTimer(true, false);
     contents_observer_->SetTimerForTest(base::WrapUnique(playback_timer_));
 
-    ASSERT_FALSE(GetStoredPlayerStatesCount());
+    SimulateInaudible();
   }
 
   bool IsTimerRunning() const { return playback_timer_->IsRunning(); }
@@ -75,10 +78,10 @@
     contents_observer_->MediaStoppedPlaying(player_info, player_id);
   }
 
-  void SimulateMutedStateChange(int id, bool muted_state) {
+  void SimulateMutedStateChange(int id, bool muted) {
     content::WebContentsObserver::MediaPlayerId player_id =
         std::make_pair(nullptr /* RenderFrameHost */, id);
-    contents_observer_->MediaMutedStateChanged(player_id, muted_state);
+    contents_observer_->MediaMutedStatusChanged(player_id, muted);
   }
 
   void SimulateIsVisible() { contents_observer_->WasShown(); }
@@ -123,6 +126,16 @@
     contents_observer_->committed_origin_ = url::Origin(url);
   }
 
+  void SimulateAudible() {
+    content::WebContentsTester::For(web_contents())
+        ->SetWasRecentlyAudible(true);
+  }
+
+  void SimulateInaudible() {
+    content::WebContentsTester::For(web_contents())
+        ->SetWasRecentlyAudible(false);
+  }
+
  private:
   // contents_observer_ auto-destroys when WebContents is destroyed.
   MediaEngagementContentsObserver* contents_observer_;
@@ -175,8 +188,8 @@
 
   web_contents()->SetAudioMuted(true);
   EXPECT_FALSE(AreConditionsMet());
-
   web_contents()->SetAudioMuted(false);
+
   SimulateIsHidden();
   EXPECT_FALSE(AreConditionsMet());
 
@@ -255,6 +268,7 @@
        SignificantPlaybackRecordedWhenTimerFires) {
   SimulatePlaybackStarted(0);
   SimulateIsVisible();
+  SimulateAudible();
   web_contents()->SetAudioMuted(false);
   SimulateResizeEvent(0, MediaEngagementContentsObserver::kSignificantSize);
   EXPECT_TRUE(IsTimerRunning());
@@ -271,10 +285,21 @@
   Navigate(url);
   ExpectScores(url, 0.0, 1, 0);
 
+  SimulateAudible();
   SimulateSignificantPlaybackTime();
   ExpectScores(url, 0.0, 1, 1);
 }
 
+TEST_F(MediaEngagementContentsObserverTest,
+       SignificantPlaybackNotRecordedIfAudioSilent) {
+  SimulatePlaybackStarted(0);
+  SimulateIsVisible();
+  SimulateInaudible();
+  web_contents()->SetAudioMuted(false);
+  EXPECT_FALSE(IsTimerRunning());
+  EXPECT_FALSE(WasSignificantPlaybackRecorded());
+}
+
 TEST_F(MediaEngagementContentsObserverTest, DoNotRecordAudiolessTrack) {
   EXPECT_EQ(0u, GetSignificantActivePlayersCount());
 
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_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 4e88d2ace..d7c6c9d 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -691,3 +691,7 @@
   EXPECT_TRUE(base::StringToSizeT(result.substr(24), &count));
   return count;
 }
+
+void WebRtcTestBase::CollectGarbage(content::WebContents* tab) const {
+  EXPECT_EQ("ok-gc", ExecuteJavascript("collectGarbage()", tab));
+}
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
index 5c16fef..5eadac5 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -222,6 +222,9 @@
   bool HasReceiverWithTrack(content::WebContents* tab,
                             std::string track_id) const;
   size_t GetNegotiationNeededCount(content::WebContents* tab) const;
+  // Performs garbage collection with "gc()". Requires command line switch
+  // |kJavaScriptFlags| with "--expose-gc".
+  void CollectGarbage(content::WebContents* tab) const;
 
  private:
   void CloseInfoBarInTab(content::WebContents* tab_contents,
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
index f935850..375b305 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
@@ -24,6 +24,8 @@
     command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
     command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
                                     "RTCRtpSender");
+    // Required by |CollectGarbage|.
+    command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
   }
 
  protected:
@@ -67,7 +69,8 @@
   VerifyRtpReceivers(right_tab_, 6);
 }
 
-IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, AddAndRemoveTracksWithoutStream) {
+IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
+                       DISABLED_AddAndRemoveTracksWithoutStream) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
@@ -92,6 +95,7 @@
   EXPECT_NE("null", audio_track_id);
   EXPECT_EQ("null", video_stream_id);
   EXPECT_NE("null", video_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_FALSE(
       HasLocalStreamWithTrack(left_tab_, audio_stream_id, audio_track_id));
   EXPECT_FALSE(
@@ -112,12 +116,14 @@
 
   // Remove first track.
   RemoveTrack(left_tab_, audio_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 1);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, kUndefined, audio_track_id));
   EXPECT_TRUE(HasRemoteStreamWithTrack(right_tab_, kUndefined, video_track_id));
@@ -127,12 +133,14 @@
 
   // Remove second track.
   RemoveTrack(left_tab_, video_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 0);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, kUndefined, audio_track_id));
   EXPECT_FALSE(
@@ -143,7 +151,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
-                       AddAndRemoveTracksWithSharedStream) {
+                       DISABLED_AddAndRemoveTracksWithSharedStream) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
@@ -165,6 +173,7 @@
   EXPECT_NE("null", video_stream_id);
   EXPECT_NE("null", video_track_id);
   EXPECT_EQ(audio_stream_id, video_stream_id);
+  CollectGarbage(left_tab_);
   // TODO(hbos): When |getLocalStreams| is updated to return the streams of all
   // senders, not just |addStream|-streams, then this will be EXPECT_TRUE.
   // https://crbug.com/738918
@@ -187,12 +196,14 @@
 
   // Remove first track.
   RemoveTrack(left_tab_, audio_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 1);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
   EXPECT_TRUE(
@@ -203,12 +214,14 @@
 
   // Remove second track.
   RemoveTrack(left_tab_, video_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 0);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
   EXPECT_FALSE(
@@ -219,7 +232,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
-                       AddAndRemoveTracksWithIndividualStreams) {
+                       DISABLED_AddAndRemoveTracksWithIndividualStreams) {
   StartServerAndOpenTabs();
 
   SetupPeerconnectionWithoutLocalStream(left_tab_);
@@ -241,6 +254,7 @@
   EXPECT_NE("null", video_stream_id);
   EXPECT_NE("null", video_track_id);
   EXPECT_NE(audio_stream_id, video_stream_id);
+  CollectGarbage(left_tab_);
   // TODO(hbos): When |getLocalStreams| is updated to return the streams of all
   // senders, not just |addStream|-streams, then this will be EXPECT_TRUE.
   // https://crbug.com/738918
@@ -263,12 +277,14 @@
 
   // Remove first track.
   RemoveTrack(left_tab_, audio_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 1);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
   EXPECT_TRUE(
@@ -279,12 +295,14 @@
 
   // Remove second track.
   RemoveTrack(left_tab_, video_track_id);
+  CollectGarbage(left_tab_);
   EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
   EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
   VerifyRtpSenders(left_tab_, 0);
   // Re-negotiate call, sets remote description again.
   NegotiateCall(left_tab_, right_tab_);
+  CollectGarbage(right_tab_);
   EXPECT_FALSE(
       HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
   EXPECT_FALSE(
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index b82634e2..e9098cca 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -8,8 +8,6 @@
 #include "base/trace_event/memory_dump_request_args.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 using ProcessMemoryDumpPtr =
@@ -17,87 +15,44 @@
 
 namespace {
 
-void EmitBrowserMemoryMetrics(const ProcessMemoryDumpPtr& pmd,
-                              ukm::UkmEntryBuilder* builder) {
-  builder->AddMetric("ProcessType",
-                     static_cast<int64_t>(
-                         memory_instrumentation::mojom::ProcessType::BROWSER));
-
+void EmitBrowserMemoryMetrics(const ProcessMemoryDumpPtr& pmd) {
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Browser2.Resident",
                                 pmd->os_dump->resident_set_kb / 1024);
-  builder->AddMetric("Resident", pmd->os_dump->resident_set_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Browser2.Malloc",
                                 pmd->chrome_dump.malloc_total_kb / 1024);
-  builder->AddMetric("Malloc", pmd->chrome_dump.malloc_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Browser2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
-  builder->AddMetric("PrivateMemoryFootprint",
-                     pmd->os_dump->private_footprint_kb / 1024);
 }
 
-void EmitRendererMemoryMetrics(const ProcessMemoryDumpPtr& pmd,
-                               ukm::UkmEntryBuilder* builder) {
-  builder->AddMetric("ProcessType",
-                     static_cast<int64_t>(
-                         memory_instrumentation::mojom::ProcessType::RENDERER));
-
+void EmitRendererMemoryMetrics(const ProcessMemoryDumpPtr& pmd) {
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.Resident",
                                 pmd->os_dump->resident_set_kb / 1024);
-  builder->AddMetric("Resident", pmd->os_dump->resident_set_kb / 1024);
-
-  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.Malloc",
-                                pmd->chrome_dump.malloc_total_kb / 1024);
-  builder->AddMetric("Malloc", pmd->chrome_dump.malloc_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Renderer2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
-  builder->AddMetric("PrivateMemoryFootprint",
-                     pmd->os_dump->private_footprint_kb / 1024);
-
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.Malloc",
+                                pmd->chrome_dump.malloc_total_kb / 1024);
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Renderer2.PartitionAlloc",
       pmd->chrome_dump.partition_alloc_total_kb / 1024);
-  builder->AddMetric("PartitionAlloc",
-                     pmd->chrome_dump.partition_alloc_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.BlinkGC",
                                 pmd->chrome_dump.blink_gc_total_kb / 1024);
-  builder->AddMetric("BlinkGC", pmd->chrome_dump.blink_gc_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.V8",
                                 pmd->chrome_dump.v8_total_kb / 1024);
-  builder->AddMetric("V8", pmd->chrome_dump.v8_total_kb / 1024);
 }
 
-void EmitGpuMemoryMetrics(const ProcessMemoryDumpPtr& pmd,
-                          ukm::UkmEntryBuilder* builder) {
-  builder->AddMetric(
-      "ProcessType",
-      static_cast<int64_t>(memory_instrumentation::mojom::ProcessType::GPU));
-
+void EmitGpuMemoryMetrics(const ProcessMemoryDumpPtr& pmd) {
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Gpu2.Resident",
                                 pmd->os_dump->resident_set_kb / 1024);
-  builder->AddMetric("Resident", pmd->os_dump->resident_set_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Gpu2.Malloc",
                                 pmd->chrome_dump.malloc_total_kb / 1024);
-  builder->AddMetric("Malloc", pmd->chrome_dump.malloc_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Gpu2.CommandBuffer",
       pmd->chrome_dump.command_buffer_total_kb / 1024);
-  builder->AddMetric("CommandBuffer",
-                     pmd->chrome_dump.command_buffer_total_kb / 1024);
-
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Gpu2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
-  builder->AddMetric("PrivateMemoryFootprint",
-                     pmd->os_dump->private_footprint_kb / 1024);
 }
 
 }  // namespace
@@ -122,16 +77,6 @@
 
 ProcessMemoryMetricsEmitter::~ProcessMemoryMetricsEmitter() {}
 
-std::unique_ptr<ukm::UkmEntryBuilder>
-ProcessMemoryMetricsEmitter::CreateUkmBuilder(const char* event_name) {
-  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
-  if (!ukm_recorder)
-    return nullptr;
-
-  const int32_t source_id = ukm_recorder->GetNewSourceID();
-  return ukm_recorder->GetEntryBuilder(source_id, event_name);
-}
-
 void ProcessMemoryMetricsEmitter::ReceivedMemoryDump(
     bool success,
     uint64_t dump_guid,
@@ -144,23 +89,15 @@
   uint32_t private_footprint_total_kb = 0;
   for (const ProcessMemoryDumpPtr& pmd : ptr->process_dumps) {
     private_footprint_total_kb += pmd->os_dump->private_footprint_kb;
-
-    // Populate a new entry for each ProcessMemoryDumpPtr in the global dump,
-    // annotating each entry with the dump GUID so that entries in the same
-    // global dump can be correlated with each other.
-    // TODO(jchinlee): Add URLs.
-    std::unique_ptr<ukm::UkmEntryBuilder> builder =
-        CreateUkmBuilder("Memory.Experimental");
-
     switch (pmd->process_type) {
       case memory_instrumentation::mojom::ProcessType::BROWSER:
-        EmitBrowserMemoryMetrics(pmd, builder.get());
+        EmitBrowserMemoryMetrics(pmd);
         break;
       case memory_instrumentation::mojom::ProcessType::RENDERER:
-        EmitRendererMemoryMetrics(pmd, builder.get());
+        EmitRendererMemoryMetrics(pmd);
         break;
       case memory_instrumentation::mojom::ProcessType::GPU:
-        EmitGpuMemoryMetrics(pmd, builder.get());
+        EmitGpuMemoryMetrics(pmd);
         break;
       case memory_instrumentation::mojom::ProcessType::UTILITY:
       case memory_instrumentation::mojom::ProcessType::PLUGIN:
@@ -171,9 +108,4 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Total2.PrivateMemoryFootprint",
       private_footprint_total_kb / 1024);
-
-  std::unique_ptr<ukm::UkmEntryBuilder> builder =
-      CreateUkmBuilder("Memory.Experimental");
-  builder->AddMetric("Total2.PrivateMemoryFootprint",
-                     private_footprint_total_kb / 1024);
 }
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.h b/chrome/browser/metrics/process_memory_metrics_emitter.h
index fa91d276..0358a8f 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.h
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.h
@@ -8,10 +8,6 @@
 #include "base/memory/ref_counted.h"
 #include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
 
-namespace ukm {
-class UkmEntryBuilder;
-}
-
 // This class asynchronously fetches memory metrics for each process, and then
 // emits UMA metrics from those metrics.
 // Each instance is self-owned, and will delete itself once it has finished
@@ -39,9 +35,6 @@
  private:
   friend class base::RefCountedThreadSafe<ProcessMemoryMetricsEmitter>;
 
-  std::unique_ptr<ukm::UkmEntryBuilder> CreateUkmBuilder(
-      const char* event_name);
-
   memory_instrumentation::mojom::CoordinatorPtr coordinator_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitter);
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
deleted file mode 100644
index 1b27d2c8..0000000
--- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/metrics/process_memory_metrics_emitter.h"
-
-#include "base/containers/flat_map.h"
-#include "base/memory/ref_counted.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using GlobalMemoryDumpPtr = memory_instrumentation::mojom::GlobalMemoryDumpPtr;
-using ProcessMemoryDumpPtr =
-    memory_instrumentation::mojom::ProcessMemoryDumpPtr;
-using OSMemDumpPtr = memory_instrumentation::mojom::OSMemDumpPtr;
-using ProcessType = memory_instrumentation::mojom::ProcessType;
-
-namespace {
-
-// Provide fake to surface ReceivedMemoryDump to public visibility.
-class ProcessMemoryMetricsEmitterFake : public ProcessMemoryMetricsEmitter {
- public:
-  ProcessMemoryMetricsEmitterFake() {}
-
-  void ReceivedMemoryDump(
-      bool success,
-      uint64_t dump_guid,
-      memory_instrumentation::mojom::GlobalMemoryDumpPtr ptr) override {
-    ProcessMemoryMetricsEmitter::ReceivedMemoryDump(success, dump_guid,
-                                                    std::move(ptr));
-  }
-
- private:
-  ~ProcessMemoryMetricsEmitterFake() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterFake);
-};
-
-void PopulateBrowserMetrics(GlobalMemoryDumpPtr& global_dump,
-                            base::flat_map<const char*, int64_t>& metrics_mb) {
-  ProcessMemoryDumpPtr pmd(
-      memory_instrumentation::mojom::ProcessMemoryDump::New());
-  pmd->process_type = ProcessType::BROWSER;
-  pmd->chrome_dump.malloc_total_kb = metrics_mb["Malloc"] * 1024;
-  OSMemDumpPtr os_dump(memory_instrumentation::mojom::OSMemDump::New(
-      metrics_mb["Resident"] * 1024,
-      metrics_mb["PrivateMemoryFootprint"] * 1024));
-  pmd->os_dump = std::move(os_dump);
-  global_dump->process_dumps.push_back(std::move(pmd));
-}
-
-base::flat_map<const char*, int64_t> GetExpectedBrowserMetrics() {
-  return base::flat_map<const char*, int64_t>(
-      {
-          {"ProcessType", static_cast<int64_t>(ProcessType::BROWSER)},
-          {"Resident", 10},
-          {"Malloc", 20},
-          {"PrivateMemoryFootprint", 30},
-      },
-      base::KEEP_FIRST_OF_DUPES);
-}
-
-void PopulateRendererMetrics(GlobalMemoryDumpPtr& global_dump,
-                             base::flat_map<const char*, int64_t>& metrics_mb) {
-  ProcessMemoryDumpPtr pmd(
-      memory_instrumentation::mojom::ProcessMemoryDump::New());
-  pmd->process_type = ProcessType::RENDERER;
-  pmd->chrome_dump.malloc_total_kb = metrics_mb["Malloc"] * 1024;
-  pmd->chrome_dump.partition_alloc_total_kb =
-      metrics_mb["PartitionAlloc"] * 1024;
-  pmd->chrome_dump.blink_gc_total_kb = metrics_mb["BlinkGC"] * 1024;
-  pmd->chrome_dump.v8_total_kb = metrics_mb["V8"] * 1024;
-  OSMemDumpPtr os_dump(memory_instrumentation::mojom::OSMemDump::New(
-      metrics_mb["Resident"] * 1024,
-      metrics_mb["PrivateMemoryFootprint"] * 1024));
-  pmd->os_dump = std::move(os_dump);
-  global_dump->process_dumps.push_back(std::move(pmd));
-}
-
-base::flat_map<const char*, int64_t> GetExpectedRendererMetrics() {
-  return base::flat_map<const char*, int64_t>(
-      {
-          {"ProcessType", static_cast<int64_t>(ProcessType::RENDERER)},
-          {"Resident", 110},
-          {"Malloc", 120},
-          {"PrivateMemoryFootprint", 130},
-          {"PartitionAlloc", 140},
-          {"BlinkGC", 150},
-          {"V8", 160},
-      },
-      base::KEEP_FIRST_OF_DUPES);
-}
-
-void PopulateGpuMetrics(GlobalMemoryDumpPtr& global_dump,
-                        base::flat_map<const char*, int64_t>& metrics_mb) {
-  ProcessMemoryDumpPtr pmd(
-      memory_instrumentation::mojom::ProcessMemoryDump::New());
-  pmd->process_type = ProcessType::GPU;
-  pmd->chrome_dump.malloc_total_kb = metrics_mb["Malloc"] * 1024;
-  pmd->chrome_dump.command_buffer_total_kb = metrics_mb["CommandBuffer"] * 1024;
-  OSMemDumpPtr os_dump(memory_instrumentation::mojom::OSMemDump::New(
-      metrics_mb["Resident"] * 1024,
-      metrics_mb["PrivateMemoryFootprint"] * 1024));
-  pmd->os_dump = std::move(os_dump);
-  global_dump->process_dumps.push_back(std::move(pmd));
-}
-
-base::flat_map<const char*, int64_t> GetExpectedGpuMetrics() {
-  return base::flat_map<const char*, int64_t>(
-      {
-          {"ProcessType", static_cast<int64_t>(ProcessType::GPU)},
-          {"Resident", 210},
-          {"Malloc", 220},
-          {"PrivateMemoryFootprint", 230},
-          {"CommandBuffer", 240},
-      },
-      base::KEEP_FIRST_OF_DUPES);
-}
-
-void PopulateMetrics(GlobalMemoryDumpPtr& global_dump,
-                     ProcessType ptype,
-                     base::flat_map<const char*, int64_t>& metrics_mb) {
-  switch (ptype) {
-    case ProcessType::BROWSER:
-      PopulateBrowserMetrics(global_dump, metrics_mb);
-      return;
-    case ProcessType::RENDERER:
-      PopulateRendererMetrics(global_dump, metrics_mb);
-      return;
-    case ProcessType::GPU:
-      PopulateGpuMetrics(global_dump, metrics_mb);
-      return;
-    case ProcessType::UTILITY:
-    case ProcessType::PLUGIN:
-    case ProcessType::OTHER:
-      break;
-  }
-
-  // We shouldn't reach here.
-  FAIL() << "Unknown process type case " << ptype << ".";
-}
-
-base::flat_map<const char*, int64_t> GetExpectedProcessMetrics(
-    ProcessType ptype) {
-  switch (ptype) {
-    case ProcessType::BROWSER:
-      return GetExpectedBrowserMetrics();
-    case ProcessType::RENDERER:
-      return GetExpectedRendererMetrics();
-    case ProcessType::GPU:
-      return GetExpectedGpuMetrics();
-    case ProcessType::UTILITY:
-    case ProcessType::PLUGIN:
-    case ProcessType::OTHER:
-      break;
-  }
-
-  // We shouldn't reach here.
-  CHECK(false);
-  return base::flat_map<const char*, int64_t>();
-}
-
-}  // namespace
-
-class ProcessMemoryMetricsEmitterTest
-    : public testing::TestWithParam<ProcessType> {
- public:
-  ProcessMemoryMetricsEmitterTest() {}
-  ~ProcessMemoryMetricsEmitterTest() override {}
-
- protected:
-  void CheckMemoryUkmEntryMetrics(
-      size_t entry_num,
-      base::flat_map<const char*, int64_t> expected) {
-    const ukm::mojom::UkmEntry* entry = test_ukm_recorder_.GetEntry(entry_num);
-    CHECK(entry != nullptr);
-    EXPECT_EQ(expected.size(), entry->metrics.size());
-    for (auto it = expected.begin(); it != expected.end(); ++it) {
-      const ukm::mojom::UkmMetric* actual =
-          test_ukm_recorder_.FindMetric(entry, it->first);
-      CHECK(actual != nullptr);
-      EXPECT_EQ(it->second, actual->value);
-    }
-  }
-
-  ukm::TestUkmRecorder test_ukm_recorder_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterTest);
-};
-
-TEST_P(ProcessMemoryMetricsEmitterTest, CollectsSingleProcessUKMs) {
-  base::flat_map<const char*, int64_t> expected_metrics =
-      GetExpectedProcessMetrics(GetParam());
-  uint64_t dump_guid = 333;
-
-  GlobalMemoryDumpPtr global_dump(
-      memory_instrumentation::mojom::GlobalMemoryDump::New());
-  PopulateMetrics(global_dump, GetParam(), expected_metrics);
-
-  scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
-      new ProcessMemoryMetricsEmitterFake());
-  emitter->ReceivedMemoryDump(true, dump_guid, std::move(global_dump));
-
-  EXPECT_EQ(2u, test_ukm_recorder_.entries_count());
-  CheckMemoryUkmEntryMetrics(0, expected_metrics);
-}
-
-INSTANTIATE_TEST_CASE_P(SinglePtype,
-                        ProcessMemoryMetricsEmitterTest,
-                        testing::Values(ProcessType::BROWSER,
-                                        ProcessType::RENDERER,
-                                        ProcessType::GPU));
-
-TEST_F(ProcessMemoryMetricsEmitterTest, CollectsManyProcessUKMsSingleDump) {
-  std::vector<ProcessType> entries_ptypes = {
-      ProcessType::BROWSER, ProcessType::RENDERER, ProcessType::GPU,
-      ProcessType::GPU,     ProcessType::RENDERER, ProcessType::BROWSER,
-  };
-  uint64_t dump_guid = 333;
-
-  GlobalMemoryDumpPtr global_dump(
-      memory_instrumentation::mojom::GlobalMemoryDump::New());
-  std::vector<base::flat_map<const char*, int64_t>> entries_metrics;
-  for (const auto& ptype : entries_ptypes) {
-    auto expected_metrics = GetExpectedProcessMetrics(ptype);
-    PopulateMetrics(global_dump, ptype, expected_metrics);
-    entries_metrics.push_back(expected_metrics);
-  }
-
-  scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
-      new ProcessMemoryMetricsEmitterFake());
-  emitter->ReceivedMemoryDump(true, dump_guid, std::move(global_dump));
-
-  EXPECT_EQ(7u, test_ukm_recorder_.entries_count());
-  for (size_t i = 0; i < entries_ptypes.size(); ++i) {
-    CheckMemoryUkmEntryMetrics(i, entries_metrics[i]);
-  }
-}
-
-TEST_F(ProcessMemoryMetricsEmitterTest, CollectsManyProcessUKMsManyDumps) {
-  std::vector<std::vector<ProcessType>> entries_ptypes = {
-      {ProcessType::BROWSER, ProcessType::RENDERER, ProcessType::GPU},
-      {ProcessType::GPU, ProcessType::RENDERER, ProcessType::BROWSER},
-  };
-
-  std::vector<base::flat_map<const char*, int64_t>> entries_metrics;
-  scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
-      new ProcessMemoryMetricsEmitterFake());
-  for (int i = 0; i < 2; ++i) {
-    GlobalMemoryDumpPtr global_dump(
-        memory_instrumentation::mojom::GlobalMemoryDump::New());
-    for (const auto& ptype : entries_ptypes[i]) {
-      auto expected_metrics = GetExpectedProcessMetrics(ptype);
-      PopulateMetrics(global_dump, ptype, expected_metrics);
-      entries_metrics.push_back(expected_metrics);
-    }
-    emitter->ReceivedMemoryDump(true, i, std::move(global_dump));
-  }
-
-  EXPECT_EQ(8u, test_ukm_recorder_.entries_count());
-  for (size_t i = 0; i < entries_ptypes.size(); ++i) {
-    CheckMemoryUkmEntryMetrics(i, entries_metrics[i]);
-  }
-}
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/page_load_metrics/observers/local_network_requests_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer_unittest.cc
index 41a8ef0..7dfb79ee 100644
--- a/chrome/browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer_unittest.cc
@@ -176,11 +176,12 @@
 
   void ExpectUkmPageDomainMetric(const internal::PageAddressInfo& page,
                                  const internal::DomainType domain_type) {
-    EXPECT_EQ(1ul, ukm_tester().sources_count());
-    const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(page.url);
+    EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+    const ukm::UkmSource* source =
+        test_ukm_recorder().GetSourceForUrl(page.url);
     EXPECT_EQ(GURL(page.url), source->url());
 
-    ukm_tester().ExpectEntry(
+    test_ukm_recorder().ExpectEntry(
         *source, internal::kUkmPageDomainEventName,
         {{internal::kUkmDomainTypeName, static_cast<int>(domain_type)}});
   }
@@ -192,9 +193,10 @@
     // The page domain info UKM entry will always be created, so we expect that
     // there should be one more UKM entry than the expected number of metrics
     // entries.
-    EXPECT_EQ(expected_metrics.size() + 1, ukm_tester().entries_count());
+    EXPECT_EQ(expected_metrics.size() + 1, test_ukm_recorder().entries_count());
 
-    const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(page.url);
+    const ukm::UkmSource* source =
+        test_ukm_recorder().GetSourceForUrl(page.url);
     for (auto entry : expected_metrics) {
       std::vector<std::pair<const char*, int64_t>> metric_values = {
           {internal::kUkmResourceTypeName, entry.resource_type},
@@ -205,7 +207,7 @@
         metric_values.push_back(
             {internal::kUkmPortTypeName, static_cast<int>(entry.port_type)});
       }
-      ukm_tester().ExpectEntry(
+      test_ukm_recorder().ExpectEntry(
           *source, internal::kUkmLocalNetworkRequestsEventName, metric_values);
     }
 
@@ -220,8 +222,8 @@
 };
 
 TEST_F(LocalNetworkRequestsPageLoadMetricsObserverTest, NoMetrics) {
-  EXPECT_EQ(0ul, ukm_tester().sources_count());
-  EXPECT_EQ(0ul, ukm_tester().entries_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().sources_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 
   // Sanity check
   ExpectNoHistograms();
@@ -715,7 +717,7 @@
   }
 
   // At this point, we should still only see the domain type UKM entry.
-  EXPECT_EQ(1ul, ukm_tester().entries_count());
+  EXPECT_EQ(1ul, test_ukm_recorder().entries_count());
 
   // Close the page.
   DeleteContents();
@@ -887,7 +889,7 @@
   navigation_simulator->CommitErrorPage();
 
   // Nothing should have been generated.
-  EXPECT_EQ(0ul, ukm_tester().sources_count());
-  EXPECT_EQ(0ul, ukm_tester().entries_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().sources_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
   ExpectNoHistograms();
 }
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index 60f99b82..629922f 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -55,7 +55,7 @@
 }  // namespace
 
 PageLoadMetricsObserverTestHarness::PageLoadMetricsObserverTestHarness()
-    : ChromeRenderViewHostTestHarness(), ukm_tester_(&test_ukm_recorder_) {}
+    : ChromeRenderViewHostTestHarness() {}
 
 PageLoadMetricsObserverTestHarness::~PageLoadMetricsObserverTestHarness() {}
 
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
index 3702e0c..33db866 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -9,7 +9,6 @@
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
-#include "chrome/browser/page_load_metrics/test/ukm_tester.h"
 #include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
 #include "chrome/common/page_load_metrics/test/weak_mock_timer.h"
 #include "chrome/common/url_constants.h"
@@ -88,14 +87,13 @@
   // Gets the PageLoadExtraInfo for the committed_load_ in observer_.
   const PageLoadExtraInfo GetPageLoadExtraInfoForCommittedLoad();
 
-  const page_load_metrics::test::UkmTester& ukm_tester() const {
-    return ukm_tester_;
+  const ukm::TestUkmRecorder& test_ukm_recorder() const {
+    return test_ukm_recorder_;
   }
 
  private:
   base::HistogramTester histogram_tester_;
   ukm::TestUkmRecorder test_ukm_recorder_;
-  page_load_metrics::test::UkmTester ukm_tester_;
   MetricsWebContentsObserver* observer_;
 
   DISALLOW_COPY_AND_ASSIGN(PageLoadMetricsObserverTestHarness);
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index f81a7aa..6582d6c 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -66,8 +66,8 @@
 };
 
 TEST_F(UkmPageLoadMetricsObserverTest, NoMetrics) {
-  EXPECT_EQ(0ul, ukm_tester().sources_count());
-  EXPECT_EQ(0ul, ukm_tester().entries_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().sources_count());
+  EXPECT_EQ(0ul, test_ukm_recorder().entries_count());
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, Basic) {
@@ -94,28 +94,30 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(1ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(kTestUrl1);
+  EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(kTestUrl1);
   EXPECT_EQ(GURL(kTestUrl1), source->url());
 
-  EXPECT_GE(ukm_tester().entries_count(), 1ul);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmPageTransition,
-                            ui::PAGE_TRANSITION_LINK);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmParseStartName, 100);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmDomContentLoadedName, 200);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmFirstPaintName, 250);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmFirstContentfulPaintName, 300);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmLoadEventName, 500);
-  EXPECT_FALSE(ukm_tester().HasMetric(*source, internal::kUkmPageLoadEventName,
-                                      internal::kUkmFirstMeaningfulPaintName));
-  EXPECT_TRUE(ukm_tester().HasMetric(*source, internal::kUkmPageLoadEventName,
-                                     internal::kUkmForegroundDurationName));
+  EXPECT_GE(test_ukm_recorder().entries_count(), 1ul);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmPageTransition,
+                                   ui::PAGE_TRANSITION_LINK);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmParseStartName, 100);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmDomContentLoadedName, 200);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmFirstPaintName, 250);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmFirstContentfulPaintName, 300);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmLoadEventName, 500);
+  EXPECT_FALSE(
+      test_ukm_recorder().HasMetric(*source, internal::kUkmPageLoadEventName,
+                                    internal::kUkmFirstMeaningfulPaintName));
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source, internal::kUkmPageLoadEventName,
+                                    internal::kUkmForegroundDurationName));
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, FailedProvisionalLoad) {
@@ -132,30 +134,32 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(1ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(kTestUrl1);
+  EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(kTestUrl1);
   EXPECT_EQ(GURL(kTestUrl1), source->url());
 
-  EXPECT_GE(ukm_tester().entries_count(), 1ul);
+  EXPECT_GE(test_ukm_recorder().entries_count(), 1ul);
 
   // Make sure that only the following metrics are logged. In particular, no
   // paint/document/etc timing metrics should be logged for failed provisional
   // loads.
-  EXPECT_EQ(5, ukm_tester().CountMetricsForEventName(
+  EXPECT_EQ(5, test_ukm_recorder().CountMetricsForEventName(
                    *source, internal::kUkmPageLoadEventName));
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmPageTransition,
-                            ui::PAGE_TRANSITION_LINK);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmEffectiveConnectionType,
-                            net::EFFECTIVE_CONNECTION_TYPE_2G);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmNetErrorCode,
-                            static_cast<int64_t>(net::ERR_TIMED_OUT) * -1);
-  EXPECT_TRUE(ukm_tester().HasMetric(*source, internal::kUkmPageLoadEventName,
-                                     internal::kUkmForegroundDurationName));
-  EXPECT_TRUE(ukm_tester().HasMetric(*source, internal::kUkmPageLoadEventName,
-                                     internal::kUkmFailedProvisionaLoadName));
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmPageTransition,
+                                   ui::PAGE_TRANSITION_LINK);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmEffectiveConnectionType,
+                                   net::EFFECTIVE_CONNECTION_TYPE_2G);
+  test_ukm_recorder().ExpectMetric(
+      *source, internal::kUkmPageLoadEventName, internal::kUkmNetErrorCode,
+      static_cast<int64_t>(net::ERR_TIMED_OUT) * -1);
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source, internal::kUkmPageLoadEventName,
+                                    internal::kUkmForegroundDurationName));
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source, internal::kUkmPageLoadEventName,
+                                    internal::kUkmFailedProvisionaLoadName));
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, FirstMeaningfulPaint) {
@@ -172,15 +176,16 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(1ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(kTestUrl1);
+  EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(kTestUrl1);
   EXPECT_EQ(GURL(kTestUrl1), source->url());
 
-  EXPECT_GE(ukm_tester().entries_count(), 1ul);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmFirstMeaningfulPaintName, 600);
-  EXPECT_TRUE(ukm_tester().HasMetric(*source, internal::kUkmPageLoadEventName,
-                                     internal::kUkmForegroundDurationName));
+  EXPECT_GE(test_ukm_recorder().entries_count(), 1ul);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmFirstMeaningfulPaintName, 600);
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source, internal::kUkmPageLoadEventName,
+                                    internal::kUkmForegroundDurationName));
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, MultiplePageLoads) {
@@ -206,30 +211,37 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(2ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source1 = ukm_tester().GetSourceForUrl(kTestUrl1);
-  const ukm::UkmSource* source2 = ukm_tester().GetSourceForUrl(kTestUrl2);
+  EXPECT_EQ(2ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source1 =
+      test_ukm_recorder().GetSourceForUrl(kTestUrl1);
+  const ukm::UkmSource* source2 =
+      test_ukm_recorder().GetSourceForUrl(kTestUrl2);
   EXPECT_EQ(GURL(kTestUrl1), source1->url());
   EXPECT_EQ(GURL(kTestUrl2), source2->url());
   EXPECT_NE(source1->id(), source2->id());
 
-  EXPECT_GE(ukm_tester().entries_count(), 2ul);
+  EXPECT_GE(test_ukm_recorder().entries_count(), 2ul);
 
-  ukm_tester().ExpectMetric(*source1, internal::kUkmPageLoadEventName,
-                            internal::kUkmFirstContentfulPaintName, 200);
-  EXPECT_FALSE(ukm_tester().HasMetric(*source2, internal::kUkmPageLoadEventName,
-                                      internal::kUkmFirstMeaningfulPaintName));
-  EXPECT_TRUE(ukm_tester().HasMetric(*source1, internal::kUkmPageLoadEventName,
-                                     internal::kUkmForegroundDurationName));
+  test_ukm_recorder().ExpectMetric(*source1, internal::kUkmPageLoadEventName,
+                                   internal::kUkmFirstContentfulPaintName, 200);
+  EXPECT_FALSE(
+      test_ukm_recorder().HasMetric(*source2, internal::kUkmPageLoadEventName,
+                                    internal::kUkmFirstMeaningfulPaintName));
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source1, internal::kUkmPageLoadEventName,
+                                    internal::kUkmForegroundDurationName));
 
-  EXPECT_FALSE(ukm_tester().HasMetric(*source2, internal::kUkmPageLoadEventName,
-                                      internal::kUkmParseStartName));
-  EXPECT_FALSE(ukm_tester().HasMetric(*source2, internal::kUkmPageLoadEventName,
-                                      internal::kUkmFirstContentfulPaintName));
-  EXPECT_FALSE(ukm_tester().HasMetric(*source2, internal::kUkmPageLoadEventName,
-                                      internal::kUkmFirstMeaningfulPaintName));
-  EXPECT_TRUE(ukm_tester().HasMetric(*source2, internal::kUkmPageLoadEventName,
-                                     internal::kUkmForegroundDurationName));
+  EXPECT_FALSE(test_ukm_recorder().HasMetric(
+      *source2, internal::kUkmPageLoadEventName, internal::kUkmParseStartName));
+  EXPECT_FALSE(
+      test_ukm_recorder().HasMetric(*source2, internal::kUkmPageLoadEventName,
+                                    internal::kUkmFirstContentfulPaintName));
+  EXPECT_FALSE(
+      test_ukm_recorder().HasMetric(*source2, internal::kUkmPageLoadEventName,
+                                    internal::kUkmFirstMeaningfulPaintName));
+  EXPECT_TRUE(
+      test_ukm_recorder().HasMetric(*source2, internal::kUkmPageLoadEventName,
+                                    internal::kUkmForegroundDurationName));
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, NetworkQualityEstimates) {
@@ -245,18 +257,18 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(1ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(kTestUrl1);
+  EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(kTestUrl1);
   EXPECT_EQ(GURL(kTestUrl1), source->url());
 
-  EXPECT_GE(ukm_tester().entries_count(), 1ul);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmEffectiveConnectionType,
-                            net::EFFECTIVE_CONNECTION_TYPE_3G);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmHttpRttEstimate, 100);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmTransportRttEstimate, 200);
+  EXPECT_GE(test_ukm_recorder().entries_count(), 1ul);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmEffectiveConnectionType,
+                                   net::EFFECTIVE_CONNECTION_TYPE_3G);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmHttpRttEstimate, 100);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmTransportRttEstimate, 200);
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, PageTransitionReload) {
@@ -267,12 +279,12 @@
   // Simulate closing the tab.
   DeleteContents();
 
-  EXPECT_EQ(1ul, ukm_tester().sources_count());
-  const ukm::UkmSource* source = ukm_tester().GetSourceForUrl(kTestUrl1);
+  EXPECT_EQ(1ul, test_ukm_recorder().sources_count());
+  const ukm::UkmSource* source = test_ukm_recorder().GetSourceForUrl(kTestUrl1);
   EXPECT_EQ(GURL(kTestUrl1), source->url());
 
-  EXPECT_GE(ukm_tester().entries_count(), 1ul);
-  ukm_tester().ExpectMetric(*source, internal::kUkmPageLoadEventName,
-                            internal::kUkmPageTransition,
-                            ui::PAGE_TRANSITION_RELOAD);
+  EXPECT_GE(test_ukm_recorder().entries_count(), 1ul);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmPageTransition,
+                                   ui::PAGE_TRANSITION_RELOAD);
 }
diff --git a/chrome/browser/page_load_metrics/test/ukm_tester.cc b/chrome/browser/page_load_metrics/test/ukm_tester.cc
deleted file mode 100644
index b4cd630..0000000
--- a/chrome/browser/page_load_metrics/test/ukm_tester.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/page_load_metrics/test/ukm_tester.h"
-
-#include <algorithm>
-#include <iterator>
-
-#include "base/metrics/metrics_hashes.h"
-#include "components/ukm/ukm_source.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Provides a single merged ukm::mojom::UkmEntry proto that contains all metrics
-// from the given |entries|. |entries| must be non-empty, and all |entries| must
-// have the same |source_id| and |event_hash|.
-ukm::mojom::UkmEntryPtr GetMergedEntry(
-    const std::vector<const ukm::mojom::UkmEntry*>& entries) {
-  EXPECT_FALSE(entries.empty());
-  ukm::mojom::UkmEntryPtr merged_entry = ukm::mojom::UkmEntry::New();
-  for (const auto* entry : entries) {
-    if (merged_entry->event_hash) {
-      EXPECT_EQ(merged_entry->source_id, entry->source_id);
-      EXPECT_EQ(merged_entry->event_hash, entry->event_hash);
-    } else {
-      merged_entry->event_hash = entry->event_hash;
-      merged_entry->source_id = entry->source_id;
-    }
-    for (const auto& metric : entry->metrics) {
-      merged_entry->metrics.emplace_back(metric->Clone());
-    }
-  }
-  return merged_entry;
-}
-
-std::vector<int64_t> GetValuesForMetric(const ukm::mojom::UkmEntry* entry,
-                                        const char* metric_name) {
-  std::vector<int64_t> values;
-  const uint64_t metric_hash = base::HashMetricName(metric_name);
-  for (const auto& metric : entry->metrics) {
-    if (metric->metric_hash == metric_hash)
-      values.push_back(metric->value);
-  }
-  return values;
-}
-
-}  // namespace
-
-namespace page_load_metrics {
-namespace test {
-
-UkmTester::UkmTester(ukm::TestUkmRecorder* test_ukm_recorder)
-    : test_ukm_recorder_(test_ukm_recorder) {}
-
-const ukm::UkmSource* UkmTester::GetSourceForUrl(const char* url) const {
-  std::vector<const ukm::UkmSource*> matching_sources = GetSourcesForUrl(url);
-  EXPECT_LE(1ul, matching_sources.size());
-  return matching_sources.empty() ? nullptr : matching_sources.back();
-}
-
-std::vector<const ukm::UkmSource*> UkmTester::GetSourcesForUrl(
-    const char* url) const {
-  std::vector<const ukm::UkmSource*> matching_sources;
-  for (const auto& candidate : test_ukm_recorder_->GetSources()) {
-    if (candidate.second->url() == url)
-      matching_sources.push_back(candidate.second.get());
-  }
-  return matching_sources;
-}
-
-std::vector<const ukm::mojom::UkmEntry*> UkmTester::GetEntriesForSourceID(
-    ukm::SourceId source_id,
-    const char* event_name) const {
-  const uint64_t event_hash = base::HashMetricName(event_name);
-  std::vector<const ukm::mojom::UkmEntry*> entries;
-  for (size_t i = 0; i < entries_count(); ++i) {
-    const ukm::mojom::UkmEntry* entry = test_ukm_recorder_->GetEntry(i);
-    if (entry->source_id == source_id && entry->event_hash == event_hash) {
-      entries.push_back(entry);
-    }
-  }
-  return entries;
-}
-
-ukm::mojom::UkmEntryPtr UkmTester::GetMergedEntryForSourceID(
-    ukm::SourceId source_id,
-    const char* event_name) const {
-  ukm::mojom::UkmEntryPtr entry =
-      GetMergedEntry(GetEntriesForSourceID(source_id, event_name));
-  EXPECT_EQ(source_id, entry->source_id);
-  EXPECT_EQ(base::HashMetricName(event_name), entry->event_hash);
-  return entry;
-}
-
-bool UkmTester::HasEntry(const ukm::UkmSource& source,
-                         const char* event_name) const {
-  return CountEntries(source, event_name) > 0;
-}
-
-int UkmTester::CountEntries(const ukm::UkmSource& source,
-                            const char* event_name) const {
-  return GetEntriesForSourceID(source.id(), event_name).size();
-}
-
-void UkmTester::ExpectEntry(const ukm::UkmSource& source,
-                            const char* event_name,
-                            const std::vector<std::pair<const char*, int64_t>>&
-                                expected_metrics) const {
-  // Produce a sorted view of the expected metrics, since order is not
-  // significant.
-  std::vector<std::pair<uint64_t, int64_t>> sorted_expected_metrics;
-  std::transform(expected_metrics.begin(), expected_metrics.end(),
-                 std::back_inserter(sorted_expected_metrics),
-                 [](const std::pair<const char*, int64_t>& metric) {
-                   return std::make_pair(base::HashMetricName(metric.first),
-                                         metric.second);
-                 });
-  std::sort(sorted_expected_metrics.begin(), sorted_expected_metrics.end());
-
-  std::vector<const ukm::mojom::UkmEntry*> candidate_entries =
-      GetEntriesForSourceID(source.id(), event_name);
-
-  // Produce a view of each matching entry's metrics that can be compared with
-  // sorted_expected_metrics.
-  std::vector<std::vector<std::pair<uint64_t, int64_t>>> candidate_metrics;
-  std::transform(candidate_entries.begin(), candidate_entries.end(),
-                 std::back_inserter(candidate_metrics),
-                 [](const ukm::mojom::UkmEntry* candidate_entry) {
-                   std::vector<std::pair<uint64_t, int64_t>> metrics;
-                   std::transform(candidate_entry->metrics.begin(),
-                                  candidate_entry->metrics.end(),
-                                  std::back_inserter(metrics),
-                                  [](const ukm::mojom::UkmMetricPtr& metric) {
-                                    return std::make_pair(metric->metric_hash,
-                                                          metric->value);
-                                  });
-                   std::sort(metrics.begin(), metrics.end());
-                   return metrics;
-                 });
-
-  if (std::find(candidate_metrics.begin(), candidate_metrics.end(),
-                sorted_expected_metrics) == candidate_metrics.end()) {
-    FAIL() << "Failed to find metrics for event: " << event_name;
-  }
-}
-
-int UkmTester::CountMetricsForEventName(const ukm::UkmSource& source,
-                                        const char* event_name) const {
-  ukm::mojom::UkmEntryPtr entry =
-      GetMergedEntryForSourceID(source.id(), event_name);
-  return entry.get() ? entry->metrics.size() : 0;
-}
-
-bool UkmTester::HasMetric(const ukm::UkmSource& source,
-                          const char* event_name,
-                          const char* metric_name) const {
-  return CountMetrics(source, event_name, metric_name) > 0;
-}
-
-int UkmTester::CountMetrics(const ukm::UkmSource& source,
-                            const char* event_name,
-                            const char* metric_name) const {
-  ukm::mojom::UkmEntryPtr entry =
-      GetMergedEntryForSourceID(source.id(), event_name);
-  return GetValuesForMetric(entry.get(), metric_name).size();
-}
-
-void UkmTester::ExpectMetric(const ukm::UkmSource& source,
-                             const char* event_name,
-                             const char* metric_name,
-                             int64_t expected_value) const {
-  ExpectMetrics(source, event_name, metric_name, {expected_value});
-}
-
-void UkmTester::ExpectMetrics(
-    const ukm::UkmSource& source,
-    const char* event_name,
-    const char* metric_name,
-    const std::vector<int64_t>& expected_values) const {
-  ukm::mojom::UkmEntryPtr entry =
-      GetMergedEntryForSourceID(source.id(), event_name);
-
-  // Make sure both vectors are sorted before comparing, since order is not
-  // significant.
-  std::vector<int64_t> sorted_expected_values(expected_values);
-  std::sort(sorted_expected_values.begin(), sorted_expected_values.end());
-
-  std::vector<int64_t> actual_values =
-      GetValuesForMetric(entry.get(), metric_name);
-  std::sort(actual_values.begin(), actual_values.end());
-
-  EXPECT_EQ(actual_values, sorted_expected_values)
-      << "Failed to find expected_values for metric: " << metric_name;
-}
-
-}  // namespace test
-}  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/test/ukm_tester.h b/chrome/browser/page_load_metrics/test/ukm_tester.h
deleted file mode 100644
index c115cbc..0000000
--- a/chrome/browser/page_load_metrics/test/ukm_tester.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
-#define CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
-
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/ukm/test_ukm_recorder.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
-
-namespace ukm {
-class UkmSource;
-}  // namespace ukm
-
-namespace page_load_metrics {
-namespace test {
-
-// UkmTester provides utilities for testing the logging of UKM sources, events,
-// and metrics.
-class UkmTester {
- public:
-  explicit UkmTester(ukm::TestUkmRecorder* test_ukm_recorder);
-
-  // Number of UKM sources recorded.
-  size_t sources_count() const { return test_ukm_recorder_->sources_count(); }
-
-  // Number of UKM entries recorded.
-  size_t entries_count() const { return test_ukm_recorder_->entries_count(); }
-
-  const ukm::UkmSource* GetSourceForUrl(const char* url) const;
-
-  std::vector<const ukm::UkmSource*> GetSourcesForUrl(const char* url) const;
-
-  // Returns whether the given UKM |source| has an entry with the given
-  // |event_name|.
-  bool HasEntry(const ukm::UkmSource& source,
-                const char* event_name) const WARN_UNUSED_RESULT;
-
-  // Returns the number of metrics recorded for the given UKM |source| and
-  // |event_name|.
-  int CountMetricsForEventName(const ukm::UkmSource& source,
-                               const char* event_name) const;
-
-  // Returns whether a metric with the given |metric_name| was recorded for the
-  // given UKM |source| and |event_name|.
-  bool HasMetric(const ukm::UkmSource& source,
-                 const char* event_name,
-                 const char* metric_name) const WARN_UNUSED_RESULT;
-
-  // Returns the number of metrics recorded with the given |metric_name|, for
-  // the given UKM |source| and |event_name|.
-  int CountMetrics(const ukm::UkmSource& source,
-                   const char* event_name,
-                   const char* metric_name) const WARN_UNUSED_RESULT;
-
-  // Expects that a single metric was recorded with the given |expected_value|,
-  // for the given |source| and |event_name|. This is shorthand for calling
-  // ExpectMetrics with a single value in the expected values vector.
-  void ExpectMetric(const ukm::UkmSource& source,
-                    const char* event_name,
-                    const char* metric_name,
-                    int64_t expected_value) const;
-
-  // Expects that metrics were recorded with the given |expected_values|, for
-  // the given |source| and |event_name|. The order of |expected_values| is not
-  // significant.
-  void ExpectMetrics(const ukm::UkmSource& source,
-                     const char* event_name,
-                     const char* metric_name,
-                     const std::vector<int64_t>& expected_values) const;
-
-  // UKM entries that may be recorded multiple times for a single source may
-  // need to verify that an expected number of UKM entries were logged. The
-  // utility methods below can be used to verify expected entries. UKM entries
-  // that aren't recorded multiple times per source should prefer using
-  // HasMetric/CountMetrics/ExpectMetric(s) above.
-
-  // Returns the number of entries recorded with the given |event_name|, for the
-  // given UKM |source|.
-  int CountEntries(const ukm::UkmSource& source, const char* event_name) const;
-
-  // Expects that an entry with the given |expected_metrics| was recorded, for
-  // the given |source| and |event_name|. The order of |expected_metrics| is not
-  // significant. |expected_metrics| contains (metric name,metric value) pairs.
-  void ExpectEntry(const ukm::UkmSource& source,
-                   const char* event_name,
-                   const std::vector<std::pair<const char*, int64_t>>&
-                       expected_metrics) const;
-
- private:
-  ukm::mojom::UkmEntryPtr GetMergedEntryForSourceID(
-      ukm::SourceId source_id,
-      const char* event_name) const;
-
-  std::vector<const ukm::mojom::UkmEntry*> GetEntriesForSourceID(
-      ukm::SourceId source_id,
-      const char* event_name) const;
-
-  const ukm::TestUkmRecorder* test_ukm_recorder_;
-
-  DISALLOW_COPY_AND_ASSIGN(UkmTester);
-};
-
-}  // namespace test
-}  // namespace page_load_metrics
-
-#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_TEST_UKM_TESTER_H_
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc
index 5a5fa13..a43bd707 100644
--- a/chrome/browser/password_manager/password_manager_test_base.cc
+++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/password_manager/password_manager_test_base.h"
 
+#include <map>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -453,7 +456,8 @@
       PasswordStoreFactory::GetForProfile(browser()->profile(),
                                           ServiceAccessType::IMPLICIT_ACCESS);
   PasswordStoreResultsObserver syncer;
-  password_store->GetAutofillableLoginsWithAffiliatedRealms(&syncer);
+  password_store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
+      &syncer);
   syncer.Wait();
 }
 
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/chromeos/zip_archiver/BUILD.gn b/chrome/browser/resources/chromeos/zip_archiver/BUILD.gn
new file mode 100644
index 0000000..68fc2b9
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/BUILD.gn
@@ -0,0 +1,93 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+group("zip_archiver") {
+  deps = [
+    ":zip_archiver_css",
+    ":zip_archiver_html",
+    ":zip_archiver_icons",
+    ":zip_archiver_js",
+    ":zip_archiver_root",
+  ]
+}
+
+zip_archiver_dir = "$root_out_dir/resources/chromeos/zip_archiver"
+
+copy("zip_archiver_css") {
+  sources = [
+    "css/passphrase-dialog.css",
+    "css/passphrase.css",
+  ]
+
+  outputs = [
+    "$zip_archiver_dir/css/{{source_file_part}}",
+  ]
+}
+
+copy("zip_archiver_html") {
+  sources = [
+    "html/compressor.html",
+    "html/passphrase-dialog.html",
+    "html/passphrase.html",
+  ]
+
+  outputs = [
+    "$zip_archiver_dir/html/{{source_file_part}}",
+  ]
+}
+
+copy("zip_archiver_icons") {
+  sources = [
+    "icons/icon128.png",
+    "icons/icon16.png",
+    "icons/icon32.png",
+    "icons/icon64.png",
+    "icons/icon96.png",
+  ]
+
+  outputs = [
+    "$zip_archiver_dir/icons/{{source_file_part}}",
+  ]
+}
+
+copy("zip_archiver_js") {
+  sources = [
+    "js/app.js",
+    "js/background.js",
+    "js/build-config.js",
+    "js/compressor-foreground.js",
+    "js/compressor.js",
+    "js/decompressor.js",
+    "js/passphrase-dialog.js",
+    "js/passphrase-manager.js",
+    "js/request.js",
+    "js/types.js",
+    "js/unpacker.js",
+    "js/volume.js",
+  ]
+
+  outputs = [
+    "$zip_archiver_dir/js/{{source_file_part}}",
+  ]
+}
+
+copy("zip_archiver_root") {
+  pexe_dir = get_label_info(
+          "//chrome/browser/resources/chromeos/zip_archiver/cpp:zip_archiver_pnacl(//build/toolchain/nacl:newlib_pnacl)",
+          "root_out_dir")
+
+  deps = [
+    "//chrome/browser/resources/chromeos/zip_archiver/cpp:zip_archiver_pnacl(//build/toolchain/nacl:newlib_pnacl)",
+  ]
+
+  sources = [
+    "$pexe_dir/zip_archiver_pnacl.pexe",
+    "manifest.json",
+    "module.nmf",
+  ]
+
+  outputs = [
+    "$zip_archiver_dir/{{source_file_part}}",
+  ]
+}
diff --git a/ui/file_manager/zip_archiver/DEPS b/chrome/browser/resources/chromeos/zip_archiver/DEPS
similarity index 64%
rename from ui/file_manager/zip_archiver/DEPS
rename to chrome/browser/resources/chromeos/zip_archiver/DEPS
index b9482469..7d97a26 100644
--- a/ui/file_manager/zip_archiver/DEPS
+++ b/chrome/browser/resources/chromeos/zip_archiver/DEPS
@@ -1,6 +1,6 @@
 include_rules = [
-  "+ppapi",
-  "+third_party/zlib",
   "+native_client_sdk/src/libraries/ppapi_simple",
-  "+testing/gtest"
+  "+ppapi",
+  "+testing/gtest",
+  "+third_party/minizip",
 ]
diff --git a/ui/file_manager/zip_archiver/LICENSE b/chrome/browser/resources/chromeos/zip_archiver/LICENSE
similarity index 100%
rename from ui/file_manager/zip_archiver/LICENSE
rename to chrome/browser/resources/chromeos/zip_archiver/LICENSE
diff --git a/ui/file_manager/zip_archiver/Makefile b/chrome/browser/resources/chromeos/zip_archiver/Makefile
similarity index 100%
rename from ui/file_manager/zip_archiver/Makefile
rename to chrome/browser/resources/chromeos/zip_archiver/Makefile
diff --git a/ui/file_manager/zip_archiver/Makefile.package b/chrome/browser/resources/chromeos/zip_archiver/Makefile.package
similarity index 100%
rename from ui/file_manager/zip_archiver/Makefile.package
rename to chrome/browser/resources/chromeos/zip_archiver/Makefile.package
diff --git a/ui/file_manager/zip_archiver/Makefile.pnacl b/chrome/browser/resources/chromeos/zip_archiver/Makefile.pnacl
similarity index 100%
rename from ui/file_manager/zip_archiver/Makefile.pnacl
rename to chrome/browser/resources/chromeos/zip_archiver/Makefile.pnacl
diff --git a/ui/file_manager/zip_archiver/README.md b/chrome/browser/resources/chromeos/zip_archiver/README.md
similarity index 100%
rename from ui/file_manager/zip_archiver/README.md
rename to chrome/browser/resources/chromeos/zip_archiver/README.md
diff --git a/ui/file_manager/zip_archiver/_locales/ar/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ar/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ar/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ar/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/bg/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/bg/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/bg/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/bg/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ca/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ca/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ca/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ca/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/cs/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/cs/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/cs/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/cs/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/da/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/da/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/da/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/da/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/de/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/de/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/de/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/de/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/el/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/el/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/el/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/el/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/en/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/en/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/en/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/en/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/en_GB/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/en_GB/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/en_GB/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/en_GB/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/es/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/es/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/es/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/es/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/es_419/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/es_419/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/es_419/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/es_419/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/et/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/et/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/et/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/et/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/fa/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/fa/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/fa/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/fa/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/fi/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/fi/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/fi/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/fi/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/fil/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/fil/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/fil/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/fil/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/fr/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/fr/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/fr/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/fr/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/he/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/he/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/he/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/he/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/hi/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/hi/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/hi/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/hi/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/hr/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/hr/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/hr/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/hr/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/hu/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/hu/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/hu/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/hu/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/id/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/id/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/id/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/id/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/it/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/it/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/it/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/it/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ja/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ja/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ja/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ja/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ko/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ko/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ko/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ko/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/lt/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/lt/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/lt/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/lt/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/lv/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/lv/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/lv/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/lv/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ms/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ms/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ms/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ms/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/nl/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/nl/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/nl/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/nl/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/no/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/no/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/no/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/no/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/pl/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/pl/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/pl/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/pl/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/pt_BR/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/pt_BR/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/pt_BR/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/pt_BR/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/pt_PT/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/pt_PT/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/pt_PT/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/pt_PT/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ro/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ro/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ro/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ro/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/ru/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/ru/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/ru/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/ru/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/sk/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/sk/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/sk/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/sk/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/sl/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/sl/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/sl/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/sl/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/sr/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/sr/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/sr/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/sr/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/sv/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/sv/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/sv/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/sv/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/th/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/th/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/th/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/th/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/tr/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/tr/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/tr/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/tr/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/uk/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/uk/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/uk/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/uk/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/vi/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/vi/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/vi/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/vi/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/zh_CN/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/zh_CN/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/zh_CN/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/zh_CN/messages.json
diff --git a/ui/file_manager/zip_archiver/_locales/zh_TW/messages.json b/chrome/browser/resources/chromeos/zip_archiver/_locales/zh_TW/messages.json
similarity index 100%
rename from ui/file_manager/zip_archiver/_locales/zh_TW/messages.json
rename to chrome/browser/resources/chromeos/zip_archiver/_locales/zh_TW/messages.json
diff --git a/ui/file_manager/zip_archiver/cpp/BUILD.gn b/chrome/browser/resources/chromeos/zip_archiver/cpp/BUILD.gn
similarity index 94%
rename from ui/file_manager/zip_archiver/cpp/BUILD.gn
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/BUILD.gn
index dfba9c8..c7294e3 100644
--- a/ui/file_manager/zip_archiver/cpp/BUILD.gn
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+assert(is_nacl, "This file should only be built in NaCl")
+
 executable("zip_archiver_pnacl") {
   sources = [
     "compressor.cc",
diff --git a/ui/file_manager/zip_archiver/cpp/compressor.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.cc
similarity index 77%
rename from ui/file_manager/zip_archiver/cpp/compressor.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.cc
index 1881c2ab..771e1751 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.cc
@@ -15,10 +15,11 @@
 namespace {
 
 // An internal implementation of JavaScriptCompressorRequestorInterface.
-class JavaScriptCompressorRequestor : public JavaScriptCompressorRequestorInterface {
+class JavaScriptCompressorRequestor
+    : public JavaScriptCompressorRequestorInterface {
  public:
-  explicit JavaScriptCompressorRequestor(Compressor* compressor) :
-      compressor_(compressor) {}
+  explicit JavaScriptCompressorRequestor(Compressor* compressor)
+      : compressor_(compressor) {}
 
   virtual void WriteChunkRequest(int64_t offset,
                                  int64_t length,
@@ -46,10 +47,8 @@
       worker_(instance_handle),
       callback_factory_(this) {
   requestor_ = new JavaScriptCompressorRequestor(this);
-  compressor_stream_ =
-      new CompressorIOJavaScriptStream(requestor_);
-  compressor_archive_ =
-      new CompressorArchiveMinizip(compressor_stream_);
+  compressor_stream_ = new CompressorIOJavaScriptStream(requestor_);
+  compressor_archive_ = new CompressorArchiveMinizip(compressor_stream_);
 }
 
 Compressor::~Compressor() {
@@ -65,9 +64,8 @@
 
 void Compressor::CreateArchive() {
   if (!compressor_archive_->CreateArchive()) {
-    message_sender_->SendCompressorError(
-        compressor_id_,
-        compressor_archive_->error_message());
+    message_sender_->SendCompressorError(compressor_id_,
+                                         compressor_archive_->error_message());
     return;
   }
   message_sender_->SendCreateArchiveDone(compressor_id_);
@@ -81,8 +79,7 @@
 void Compressor::AddToArchiveCallback(int32_t,
                                       const pp::VarDictionary& dictionary) {
   PP_DCHECK(dictionary.Get(request::key::kPathname).is_string());
-  std::string pathname =
-      dictionary.Get(request::key::kPathname).AsString();
+  std::string pathname = dictionary.Get(request::key::kPathname).AsString();
 
   PP_DCHECK(dictionary.Get(request::key::kFileSize).is_string());
   int64_t file_size =
@@ -90,20 +87,17 @@
   PP_DCHECK(file_size >= 0);
 
   PP_DCHECK(dictionary.Get(request::key::kIsDirectory).is_bool());
-  bool is_directory =
-      dictionary.Get(request::key::kIsDirectory).AsBool();
+  bool is_directory = dictionary.Get(request::key::kIsDirectory).AsBool();
 
   PP_DCHECK(dictionary.Get(request::key::kModificationTime).is_string());
   // Since modification_time is milliseconds, we hold the value in int64_t.
-  int64_t modification_time =
-      static_cast<int64_t>(request::GetInt64FromString(dictionary,
-                                               request::key::kModificationTime));
+  int64_t modification_time = static_cast<int64_t>(
+      request::GetInt64FromString(dictionary, request::key::kModificationTime));
 
-  if (!compressor_archive_->AddToArchive(
-      pathname, file_size, modification_time, is_directory)) {
-    message_sender_->SendCompressorError(
-        compressor_id_,
-        compressor_archive_->error_message());
+  if (!compressor_archive_->AddToArchive(pathname, file_size, modification_time,
+                                         is_directory)) {
+    message_sender_->SendCompressorError(compressor_id_,
+                                         compressor_archive_->error_message());
     return;
   }
   message_sender_->SendAddToArchiveDone(compressor_id_);
@@ -130,16 +124,14 @@
 
 void Compressor::CloseArchive(const pp::VarDictionary& dictionary) {
   PP_DCHECK(dictionary.Get(request::key::kHasError).is_bool());
-  bool has_error =
-      dictionary.Get(request::key::kHasError).AsBool();
+  bool has_error = dictionary.Get(request::key::kHasError).AsBool();
 
   // If an error has occurred, no more write chunk requests are sent and
   // CloseArchive() can be safely called in the main thread.
   if (has_error) {
     if (!compressor_archive_->CloseArchive(has_error)) {
       message_sender_->SendCompressorError(
-          compressor_id_,
-          compressor_archive_->error_message());
+          compressor_id_, compressor_archive_->error_message());
       return;
     }
     message_sender_->SendCloseArchiveDone(compressor_id_);
@@ -151,9 +143,8 @@
 
 void Compressor::CloseArchiveCallback(int32_t, bool has_error) {
   if (!compressor_archive_->CloseArchive(has_error)) {
-    message_sender_->SendCompressorError(
-        compressor_id_,
-        compressor_archive_->error_message());
+    message_sender_->SendCompressorError(compressor_id_,
+                                         compressor_archive_->error_message());
     return;
   }
   message_sender_->SendCloseArchiveDone(compressor_id_);
diff --git a/ui/file_manager/zip_archiver/cpp/compressor.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.h
similarity index 92%
rename from ui/file_manager/zip_archiver/cpp/compressor.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.h
index 21436bc..ebaeb962 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor.h
@@ -2,22 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPRESSOR_H_
-#define COMPRESSOR_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_H_
 
-#include <ctime>
 #include <pthread.h>
-
-#include "ppapi/cpp/instance_handle.h"
-#include "ppapi/cpp/var_array_buffer.h"
-#include "ppapi/cpp/var_dictionary.h"
-#include "ppapi/utility/completion_callback_factory.h"
-#include "ppapi/utility/threading/simple_thread.h"
+#include <ctime>
 
 #include "compressor_archive.h"
 #include "compressor_stream.h"
 #include "javascript_compressor_requestor_interface.h"
 #include "javascript_message_sender_interface.h"
+#include "ppapi/cpp/instance_handle.h"
+#include "ppapi/cpp/var_array_buffer.h"
+#include "ppapi/cpp/var_dictionary.h"
+#include "ppapi/utility/completion_callback_factory.h"
+#include "ppapi/utility/threading/simple_thread.h"
 
 // Handles all packing operations like creating archive objects and writing data
 // onto the archive.
@@ -57,7 +56,6 @@
   int compressor_id() { return compressor_id_; }
 
  private:
-
   // A callback helper for AddToArchive.
   void AddToArchiveCallback(int32_t, const pp::VarDictionary& dictionary);
 
@@ -89,4 +87,4 @@
   CompressorStream* compressor_stream_;
 };
 
-#endif  /// COMPRESSOR_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_H_
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_archive.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive.h
similarity index 83%
rename from ui/file_manager/zip_archiver/cpp/compressor_archive.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive.h
index edef665..95a6ba4 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_archive.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPRESSSOR_ARCHIVE_H_
-#define COMPRESSSOR_ARCHIVE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_H_
 
 #include "compressor_io_javascript_stream.h"
 
@@ -12,7 +12,7 @@
 class CompressorArchive {
  public:
   explicit CompressorArchive(CompressorStream* compressor_stream)
-    : compressor_stream_(compressor_stream) {}
+      : compressor_stream_(compressor_stream) {}
 
   virtual ~CompressorArchive() {}
 
@@ -34,9 +34,9 @@
   // archive first, and then if it is a file(not a directory), requests
   // JavaScript for file chunks, compresses and writes them onto the archive
   // until all chunks of the entry are written onto the archive. This method
-  // calls IO operations, so this function must not be called in the main thread.
-  // Returns true if successful. In case of failure the error message can be
-  // obtained with CompressorArchive::error_message().
+  // calls IO operations, so this function must not be called in the main
+  // thread. Returns true if successful. In case of failure the error message
+  // can be obtained with CompressorArchive::error_message().
   virtual bool AddToArchive(const std::string& filename,
                             int64_t file_size,
                             int64_t modification_time,
@@ -59,4 +59,4 @@
   std::string error_message_;
 };
 
-#endif  // COMPRESSSOR_ARCHIVE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_H_
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.cc
similarity index 65%
rename from ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.cc
index 5901de5b7..ef48de90 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.cc
@@ -15,37 +15,40 @@
 // Called when minizip tries to open a zip archive file. We do nothing here
 // because JavaScript takes care of file opening operation.
 void* CustomArchiveOpen(void* compressor,
-                        const char* /*filename*/, int /*mode*/) {
+                        const char* /*filename*/,
+                        int /*mode*/) {
   return compressor;
 }
 
 // This function is not called because we don't unpack zip files here.
-uLong CustomArchiveRead(void* /*compressor*/, void* /*stream*/,
-                        void* /*buffur*/, uLong /*size*/) {
+uint32_t CustomArchiveRead(void* /*compressor*/,
+                           void* /*stream*/,
+                           void* /*buffur*/,
+                           uint32_t /*size*/) {
   return 0 /* Success */;
 }
 
 // Called when data chunk must be written on the archive. It copies data
 // from the given buffer processed by minizip to an array buffer and passes
 // it to compressor_stream.
-uLong CustomArchiveWrite(void* compressor,
-                         void* /*stream*/,
-                         const void* zip_buffer,
-                         uLong zip_length) {
+uint32_t CustomArchiveWrite(void* compressor,
+                            void* /*stream*/,
+                            const void* zip_buffer,
+                            uint32_t zip_length) {
   CompressorArchiveMinizip* compressor_minizip =
       static_cast<CompressorArchiveMinizip*>(compressor);
 
   int64_t written_bytes = compressor_minizip->compressor_stream()->Write(
-      compressor_minizip->offset_, zip_length,
+      compressor_minizip->offset(), zip_length,
       static_cast<const char*>(zip_buffer));
 
   if (written_bytes != zip_length)
     return 0 /* Error */;
 
   // Update offset_ and length_.
-  compressor_minizip->offset_ += written_bytes;
-  if (compressor_minizip->offset_ > compressor_minizip->length_)
-    compressor_minizip->length_ = compressor_minizip->offset_;
+  compressor_minizip->set_offset(compressor_minizip->offset() + written_bytes);
+  if (compressor_minizip->offset() > compressor_minizip->length())
+    compressor_minizip->set_length(compressor_minizip->offset());
   return static_cast<uLong>(written_bytes);
 }
 
@@ -59,26 +62,25 @@
 // Moves the current offset to the specified position.
 long CustomArchiveSeek(void* compressor,
                        void* /*stream*/,
-                       uLong offset,
+                       uint32_t offset,
                        int origin) {
   CompressorArchiveMinizip* compressor_minizip =
       static_cast<CompressorArchiveMinizip*>(compressor);
 
   if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
-    compressor_minizip->offset_ =
-        std::min(compressor_minizip->offset_ + static_cast<int64_t>(offset),
-                 compressor_minizip->length_);
+    compressor_minizip->set_offset(
+        std::min(compressor_minizip->offset() + static_cast<int64_t>(offset),
+                 compressor_minizip->length()));
     return 0 /* Success */;
   }
   if (origin == ZLIB_FILEFUNC_SEEK_END) {
-    compressor_minizip->offset_ =
-        std::max(compressor_minizip->length_ - static_cast<int64_t>(offset),
-                 0LL);
+    compressor_minizip->set_offset(std::max(
+        compressor_minizip->length() - static_cast<int64_t>(offset), 0LL));
     return 0 /* Success */;
   }
   if (origin == ZLIB_FILEFUNC_SEEK_SET) {
-    compressor_minizip->offset_ =
-        std::min(static_cast<int64_t>(offset), compressor_minizip->length_);
+    compressor_minizip->set_offset(
+        std::min(static_cast<int64_t>(offset), compressor_minizip->length()));
     return 0 /* Success */;
   }
   return -1 /* Error */;
@@ -97,7 +99,7 @@
   return 0 /* Success */;
 }
 
-} // compressor_archive_functions
+}  // namespace compressor_archive_functions
 
 CompressorArchiveMinizip::CompressorArchiveMinizip(
     CompressorStream* compressor_stream)
@@ -126,10 +128,8 @@
   zip_funcs.zerror_file = compressor_archive_functions::CustomArchiveError;
   zip_funcs.opaque = this;
 
-  zip_file_ = zipOpen2(nullptr /* pathname */,
-                       APPEND_STATUS_CREATE,
-                       nullptr /* globalcomment */,
-                       &zip_funcs);
+  zip_file_ = zipOpen2(nullptr /* pathname */, APPEND_STATUS_CREATE,
+                       nullptr /* globalcomment */, &zip_funcs);
   if (!zip_file_) {
     set_error_message(compressor_archive_constants::kCreateArchiveError);
     return false /* Error */;
@@ -138,9 +138,9 @@
 }
 
 bool CompressorArchiveMinizip::AddToArchive(const std::string& filename,
-                                               int64_t file_size,
-                                               int64_t modification_time,
-                                               bool is_directory) {
+                                            int64_t file_size,
+                                            int64_t modification_time,
+                                            bool is_directory) {
   // Minizip takes filenames that end with '/' as directories.
   std::string normalized_filename = filename;
   if (is_directory)
@@ -152,36 +152,38 @@
   base::Time tm = base::Time::FromTimeT((int64_t)modification_time / 1000);
   base::Time::Exploded exploded_time = {};
   tm.LocalExplode(&exploded_time);
-  zipfileMetadata.tmz_date.tm_sec = exploded_time.second;
-  zipfileMetadata.tmz_date.tm_min = exploded_time.minute;
-  zipfileMetadata.tmz_date.tm_hour = exploded_time.hour;
-  zipfileMetadata.tmz_date.tm_year = exploded_time.year;
-  zipfileMetadata.tmz_date.tm_mday = exploded_time.day_of_month;
+  // TODO(yawano): fix this.
+  // zipfileMetadata.tmz_date.tm_sec = exploded_time.second;
+  // zipfileMetadata.tmz_date.tm_min = exploded_time.minute;
+  // zipfileMetadata.tmz_date.tm_hour = exploded_time.hour;
+  // zipfileMetadata.tmz_date.tm_year = exploded_time.year;
+  // zipfileMetadata.tmz_date.tm_mday = exploded_time.day_of_month;
   // Convert from 1-based to 0-based.
-  zipfileMetadata.tmz_date.tm_mon = exploded_time.month - 1;
+  // zipfileMetadata.tmz_date.tm_mon = exploded_time.month - 1;
 
   // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
   // Setting the Language encoding flag so the file is told to be in utf-8.
   const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
 
-  int open_result = zipOpenNewFileInZip4(zip_file_,                      // file
-                                         normalized_filename.c_str(),// filename
-                                         &zipfileMetadata,              // zipfi
-                                         nullptr,            // extrafield_local
-                                         0u,            // size_extrafield_local
-                                         nullptr,           // extrafield_global
-                                         0u,           // size_extrafield_global
-                                         nullptr,                     // comment
-                                         Z_DEFLATED,                   // method
-                                         Z_DEFAULT_COMPRESSION,         // level
-                                         0,                               // raw
-                                         -MAX_WBITS,               // windowBits
-                                         DEF_MEM_LEVEL,              // memLevel
-                                         Z_DEFAULT_STRATEGY,         // strategy
-                                         nullptr,                    // password
-                                         0,                    // crcForCrypting
-                                         0,                     // versionMadeBy
-                                         LANGUAGE_ENCODING_FLAG);    // flagBase
+  int open_result =
+      zipOpenNewFileInZip4(zip_file_,                    // file
+                           normalized_filename.c_str(),  // filename
+                           &zipfileMetadata,             // zipfi
+                           nullptr,                      // extrafield_local
+                           0u,                       // size_extrafield_local
+                           nullptr,                  // extrafield_global
+                           0u,                       // size_extrafield_global
+                           nullptr,                  // comment
+                           Z_DEFLATED,               // method
+                           Z_DEFAULT_COMPRESSION,    // level
+                           0,                        // raw
+                           -MAX_WBITS,               // windowBits
+                           DEF_MEM_LEVEL,            // memLevel
+                           Z_DEFAULT_STRATEGY,       // strategy
+                           nullptr,                  // password
+                           0,                        // crcForCrypting
+                           0,                        // versionMadeBy
+                           LANGUAGE_ENCODING_FLAG);  // flagBase
   if (open_result != ZIP_OK) {
     CloseArchive(true /* has_error */);
     set_error_message(compressor_archive_constants::kAddToArchiveError);
@@ -192,8 +194,8 @@
   if (!is_directory) {
     int64_t remaining_size = file_size;
     while (remaining_size > 0) {
-      int64_t chunk_size = std::min(remaining_size,
-          compressor_stream_constants::kMaximumDataChunkSize);
+      int64_t chunk_size = std::min(
+          remaining_size, compressor_stream_constants::kMaximumDataChunkSize);
       PP_DCHECK(chunk_size > 0);
 
       int64_t read_bytes =
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.h
new file mode 100644
index 0000000..fe6f92a1
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_archive_minizip.h
@@ -0,0 +1,105 @@
+// 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_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_MINIZIP_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_MINIZIP_H_
+
+#include <string>
+
+#include "compressor_archive.h"
+#include "compressor_stream.h"
+#include "third_party/minizip/src/unzip.h"
+#include "third_party/minizip/src/zip.h"
+
+// A namespace with constants used by CompressorArchiveMinizip.
+namespace compressor_archive_constants {
+
+const char kCreateArchiveError[] = "Failed to create archive.";
+const char kAddToArchiveError[] = "Failed to add entry to archive.";
+const char kCloseArchiveError[] = "Failed to close archive.";
+
+}  // namespace compressor_archive_constants
+
+// A name space with custom functions passed to minizip.
+namespace compressor_archive_functions {
+
+uLong CustomArchiveWrite(void* compressor,
+                         void* stream,
+                         const void* buffer,
+                         uLong length);
+
+long CustomArchiveTell(void* compressor, void* stream);
+
+long CustomArchiveSeek(void* compressor,
+                       void* stream,
+                       uLong offset,
+                       int origin);
+
+}  // namespace compressor_archive_functions
+
+class CompressorArchiveMinizip : public CompressorArchive {
+ public:
+  explicit CompressorArchiveMinizip(CompressorStream* compressor_stream);
+
+  virtual ~CompressorArchiveMinizip();
+
+  // Creates an archive object.
+  virtual bool CreateArchive();
+
+  // Releases all resources obtained by minizip.
+  virtual bool CloseArchive(bool has_error);
+
+  // Adds an entry to the archive.
+  virtual bool AddToArchive(const std::string& filename,
+                            int64_t file_size,
+                            int64_t modification_time,
+                            bool is_directory);
+
+  // A getter function for zip_file_.
+  zipFile zip_file() const { return zip_file_; }
+
+  // Getter and setter for offset_.
+  int64_t offset() const { return offset_; }
+  void set_offset(int64_t value) { offset_ = value; }
+
+  // Getter and setter for length_.
+  int64_t length() const { return length_; }
+  void set_length(int64_t value) { length_ = value; }
+
+  // A getter function for compressor_stream.
+  CompressorStream* compressor_stream() const { return compressor_stream_; }
+
+  // Custom functions need to access private variables of
+  // CompressorArchiveMinizip frequently.
+  friend uLong compressor_archive_functions::CustomArchiveWrite(
+      void* compressor,
+      void* stream,
+      const void* buffer,
+      uLong length);
+
+  friend long compressor_archive_functions::CustomArchiveTell(void* compressor,
+                                                              void* stream);
+
+  friend long compressor_archive_functions::CustomArchiveSeek(void* compressor,
+                                                              void* stream,
+                                                              uLong offset,
+                                                              int origin);
+
+ private:
+  // An instance that takes care of all IO operations.
+  CompressorStream* compressor_stream_;
+
+  // The minizip correspondent archive object.
+  zipFile zip_file_;
+
+  // The buffer used to store the data read from JavaScript.
+  char* destination_buffer_;
+
+  // The current offset of the zip archive file.
+  int64_t offset_;
+  // The size of the zip archive file.
+  int64_t length_;
+};
+
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_ARCHIVE_MINIZIP_H_
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.cc
similarity index 92%
rename from ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.cc
index 5dc823c..974056d 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.cc
@@ -29,7 +29,7 @@
   pthread_cond_destroy(&data_written_cond_);
   pthread_cond_destroy(&available_data_cond_);
   pthread_mutex_destroy(&shared_state_lock_);
-};
+}
 
 int64_t CompressorIOJavaScriptStream::Flush() {
   pthread_mutex_lock(&shared_state_lock_);
@@ -45,8 +45,7 @@
   memcpy(array_buffer_data, buffer_, buffer_data_length_);
   array_buffer.Unmap();
 
-  requestor_->WriteChunkRequest(buffer_offset_,
-                                buffer_data_length_,
+  requestor_->WriteChunkRequest(buffer_offset_, buffer_data_length_,
                                 array_buffer);
 
   pthread_cond_wait(&data_written_cond_, &shared_state_lock_);
@@ -88,13 +87,13 @@
     // 4: The index to write is outside the buffer.
     //    If we want to write data outside the range, we first need to flush
     //    the buffer, and then cache the data in the buffer.
-    if (buffer_offset_ >= 0 && /* 1 */
+    if (buffer_offset_ >= 0 &&                                     /* 1 */
         (current_offset != buffer_offset_ + buffer_data_length_ || /* 2 */
          buffer_data_length_ + left_length >
              compressor_stream_constants::kMaximumDataChunkSize) && /* 3 */
         (current_offset < buffer_offset_ ||
          buffer_offset_ + buffer_data_length_ <
-         current_offset + left_length) /* 4 */ ) {
+             current_offset + left_length) /* 4 */) {
       pthread_mutex_unlock(&shared_state_lock_);
       int64_t bytes_to_write = buffer_data_length_;
       if (Flush() != bytes_to_write)
@@ -110,12 +109,13 @@
       buffer_offset_ = current_offset;
     // Calculate the relative offset from left_length.
     int64_t offset_in_buffer = current_offset - buffer_offset_;
-    // Copy data from zip_buffer, which is pointed by buffer_pointer, to buffer_.
+    // Copy data from zip_buffer, which is pointed by buffer_pointer, to
+    // buffer_.
     memcpy(buffer_ + offset_in_buffer, buffer_pointer, copy_length);
 
     buffer_pointer += copy_length;
-    buffer_data_length_ = std::max(
-        buffer_data_length_, offset_in_buffer + copy_length);
+    buffer_data_length_ =
+        std::max(buffer_data_length_, offset_in_buffer + copy_length);
     current_offset += copy_length;
     left_length -= copy_length;
   } while (left_length > 0);
@@ -149,8 +149,9 @@
   return read_bytes;
 }
 
-int64_t CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes,
-      pp::VarArrayBuffer* array_buffer) {
+int64_t CompressorIOJavaScriptStream::ReadFileChunkDone(
+    int64_t read_bytes,
+    pp::VarArrayBuffer* array_buffer) {
   pthread_mutex_lock(&shared_state_lock_);
 
   // JavaScript sets a negative value in read_bytes if an error occurred while
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.h
similarity index 88%
rename from ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.h
index e31307c..6b949d2 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_io_javascript_stream.h
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPRESSOR_IO_JAVSCRIPT_STREAM_H_
-#define COMPRESSOR_IO_JAVSCRIPT_STREAM_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_IO_JAVASCRIPT_STREAM_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_IO_JAVASCRIPT_STREAM_H_
 
 #include <pthread.h>
 #include <string>
 
+#include "compressor_stream.h"
+#include "javascript_compressor_requestor_interface.h"
 #include "ppapi/cpp/instance_handle.h"
 #include "ppapi/cpp/var_array_buffer.h"
 #include "ppapi/utility/completion_callback_factory.h"
 #include "ppapi/utility/threading/lock.h"
 #include "ppapi/utility/threading/simple_thread.h"
 
-#include "compressor_stream.h"
-#include "javascript_compressor_requestor_interface.h"
-
 // A namespace with constants used by CompressorArchiveMinizip.
 namespace compressor_stream_constants {
 // We need at least 256KB for MiniZip.
 const int64_t kMaximumDataChunkSize = 512 * 1024;
-}  // namespace compressor_archive_constants
+}  // namespace compressor_stream_constants
 
 class CompressorIOJavaScriptStream : public CompressorStream {
  public:
@@ -46,7 +45,7 @@
   virtual int64_t ReadFileChunkDone(int64_t read_bytes,
                                     pp::VarArrayBuffer* buffer);
 
-private:
+ private:
   // A requestor that makes calls to JavaScript to read and write chunks.
   JavaScriptCompressorRequestorInterface* requestor_;
 
@@ -80,4 +79,4 @@
   char* buffer_;
 };
 
-#endif  // COMPRESSOR_IO_JAVSCRIPT_STREAM_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_IO_JAVASCRIPT_STREAM_H_
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_stream.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_stream.h
similarity index 88%
rename from ui/file_manager/zip_archiver/cpp/compressor_stream.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_stream.h
index 6d1642ec..2fed827 100644
--- a/ui/file_manager/zip_archiver/cpp/compressor_stream.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/compressor_stream.h
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPRESSOR_STREAM_H_
-#define COMPRESSOR_STREAM_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_STREAM_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_STREAM_H_
 
 #include <string>
 
+#include "ppapi/cpp/var_array_buffer.h"
+
 // A IO class that reads and writes data from and to files through JavaScript.
 // Currently, Read() and Write() methods are not called at the same time.
 // To improve the performance, these should be called in parallel by preparing
@@ -45,4 +47,4 @@
                                     pp::VarArrayBuffer* buffer) = 0;
 };
 
-#endif  // COMPRESSOR_STREAM_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_COMPRESSOR_STREAM_H_
diff --git a/ui/file_manager/zip_archiver/cpp/javascript_compressor_requestor_interface.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_compressor_requestor_interface.h
similarity index 61%
rename from ui/file_manager/zip_archiver/cpp/javascript_compressor_requestor_interface.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_compressor_requestor_interface.h
index 0ae148fe..1493dfc 100644
--- a/ui/file_manager/zip_archiver/cpp/javascript_compressor_requestor_interface.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_compressor_requestor_interface.h
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
-#define JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
 
 #include <string>
 
+#include "ppapi/cpp/var_array_buffer.h"
+
 // Makes requests from Compressor to JavaScript.
 class JavaScriptCompressorRequestorInterface {
  public:
@@ -19,4 +21,4 @@
   virtual void ReadFileChunkRequest(int64_t length) = 0;
 };
 
-#endif  // JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_COMPRESSOR_REQUESTOR_INTERFACE_H_
diff --git a/ui/file_manager/zip_archiver/cpp/javascript_message_sender_interface.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_message_sender_interface.h
similarity index 85%
rename from ui/file_manager/zip_archiver/cpp/javascript_message_sender_interface.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_message_sender_interface.h
index e6cdae5..a7881bda 100644
--- a/ui/file_manager/zip_archiver/cpp/javascript_message_sender_interface.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_message_sender_interface.h
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
-#define JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
 
 #include <string>
 
+#include "ppapi/cpp/var_array_buffer.h"
+#include "ppapi/cpp/var_dictionary.h"
+
 // Creates and sends messages to JavaScript. Messages are send asynchronously.
 class JavaScriptMessageSenderInterface {
  public:
@@ -52,8 +55,7 @@
 
   virtual void SendCreateArchiveDone(int compressor_id) = 0;
 
-  virtual void SendReadFileChunk(int compressor_id_,
-                                 int64_t file_size) = 0;
+  virtual void SendReadFileChunk(int compressor_id_, int64_t file_size) = 0;
 
   virtual void SendWriteChunk(int compressor_id,
                               const pp::VarArrayBuffer& array_buffer,
@@ -68,4 +70,4 @@
 #define CONSOLE_LOG(fsid, rid, msg) \
   SendConsoleLog(fsid, rid, __FILE__, __LINE__, __func__, msg)
 
-#endif  // JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_MESSAGE_SENDER_INTERFACE_H_
diff --git a/ui/file_manager/zip_archiver/cpp/javascript_requestor_interface.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_requestor_interface.h
similarity index 75%
rename from ui/file_manager/zip_archiver/cpp/javascript_requestor_interface.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_requestor_interface.h
index b0c9efa..31f0b73 100644
--- a/ui/file_manager/zip_archiver/cpp/javascript_requestor_interface.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/javascript_requestor_interface.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef JAVASCRIPT_REQUESTOR_INTERFACE_H_
-#define JAVASCRIPT_REQUESTOR_INTERFACE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_REQUESTOR_INTERFACE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_REQUESTOR_INTERFACE_H_
 
 #include <string>
 
@@ -23,4 +23,4 @@
   virtual void RequestPassphrase(const std::string& request_id) = 0;
 };
 
-#endif  // JAVASCRIPT_REQUESTOR_INTERFACE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_JAVASCRIPT_REQUESTOR_INTERFACE_H_
diff --git a/ui/file_manager/zip_archiver/cpp/module.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/module.cc
similarity index 93%
rename from ui/file_manager/zip_archiver/cpp/module.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/module.cc
index 236b5d1..e8a72d5 100644
--- a/ui/file_manager/zip_archiver/cpp/module.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/module.cc
@@ -5,6 +5,7 @@
 #include <clocale>
 #include <sstream>
 
+#include "compressor.h"
 #include "ppapi/cpp/instance.h"
 #include "ppapi/cpp/instance_handle.h"
 #include "ppapi/cpp/logging.h"
@@ -12,8 +13,6 @@
 #include "ppapi/cpp/var_dictionary.h"
 #include "ppapi/utility/threading/lock.h"
 #include "ppapi/utility/threading/simple_thread.h"
-
-#include "compressor.h"
 #include "request.h"
 #include "volume.h"
 
@@ -57,8 +56,8 @@
 
   virtual void SendPassphraseRequest(const std::string& file_system_id,
                                      const std::string& request_id) {
-    JavaScriptPostMessage(request::CreateReadPassphraseRequest(
-        file_system_id, request_id));
+    JavaScriptPostMessage(
+        request::CreateReadPassphraseRequest(file_system_id, request_id));
   }
 
   virtual void SendReadMetadataDone(const std::string& file_system_id,
@@ -100,13 +99,13 @@
   }
 
   virtual void SendCreateArchiveDone(int compressor_id) {
-    JavaScriptPostMessage(request::CreateCreateArchiveDoneResponse(
-        compressor_id));
+    JavaScriptPostMessage(
+        request::CreateCreateArchiveDoneResponse(compressor_id));
   }
 
   virtual void SendReadFileChunk(int compressor_id, int64_t length) {
-    JavaScriptPostMessage(request::CreateReadFileChunkRequest(
-        compressor_id, length));
+    JavaScriptPostMessage(
+        request::CreateReadFileChunkRequest(compressor_id, length));
   }
 
   virtual void SendWriteChunk(int compressor_id,
@@ -118,13 +117,13 @@
   }
 
   virtual void SendAddToArchiveDone(int compressor_id) {
-    JavaScriptPostMessage(request::CreateAddToArchiveDoneResponse(
-        compressor_id));
+    JavaScriptPostMessage(
+        request::CreateAddToArchiveDoneResponse(compressor_id));
   }
 
   virtual void SendCloseArchiveDone(int compressor_id) {
-    JavaScriptPostMessage(request::CreateCloseArchiveDoneResponse(
-        compressor_id));
+    JavaScriptPostMessage(
+        request::CreateCloseArchiveDoneResponse(compressor_id));
   }
 
  private:
@@ -150,8 +149,7 @@
 
   virtual ~NaclArchiveInstance() {
     for (volume_iterator iterator = volumes_.begin();
-         iterator != volumes_.end();
-         ++iterator) {
+         iterator != volumes_.end(); ++iterator) {
       delete iterator->second;
     }
   }
@@ -171,11 +169,9 @@
   }
 
  private:
-
   // Processes unpack messages.
   void HandleUnpackMessage(const pp::VarDictionary& var_dict,
-      const int operation) {
-
+                           const int operation) {
     PP_DCHECK(var_dict.Get(request::key::kFileSystemId).is_string());
     std::string file_system_id =
         var_dict.Get(request::key::kFileSystemId).AsString();
@@ -233,10 +229,9 @@
 
   // Processes pack messages.
   void HandlePackMessage(const pp::VarDictionary& var_dict,
-      const int operation) {
+                         const int operation) {
     PP_DCHECK(var_dict.Get(request::key::kCompressorId).is_int());
-    int compressor_id =
-        var_dict.Get(request::key::kCompressorId).AsInt();
+    int compressor_id = var_dict.Get(request::key::kCompressorId).AsInt();
 
     switch (operation) {
       case request::CREATE_ARCHIVE: {
@@ -287,8 +282,7 @@
         new Volume(instance_handle_, file_system_id, &message_sender_);
     if (!volume->Init()) {
       message_sender_.SendFileSystemError(
-          file_system_id,
-          request_id,
+          file_system_id, request_id,
           "Could not create a volume for: " + file_system_id + ".");
       delete volume;
       return;
@@ -299,8 +293,7 @@
     PP_DCHECK(var_dict.Get(request::key::kArchiveSize).is_string());
 
     volume->ReadMetadata(
-        request_id,
-        var_dict.Get(request::key::kEncoding).AsString(),
+        request_id, var_dict.Get(request::key::kEncoding).AsString(),
         request::GetInt64FromString(var_dict, request::key::kArchiveSize));
   }
 
@@ -358,8 +351,7 @@
                 const std::string& file_system_id,
                 const std::string& request_id) {
     PP_DCHECK(var_dict.Get(request::key::kIndex).is_string());
-    int64_t index =
-        request::GetInt64FromString(var_dict, request::key::kIndex);
+    int64_t index = request::GetInt64FromString(var_dict, request::key::kIndex);
 
     PP_DCHECK(var_dict.Get(request::key::kEncoding).is_string());
     std::string encoding(var_dict.Get(request::key::kEncoding).AsString());
@@ -423,8 +415,7 @@
     compressor->CreateArchive();
   }
 
-  void AddToArchive(const pp::VarDictionary& var_dict,
-                    int compressor_id) {
+  void AddToArchive(const pp::VarDictionary& var_dict, int compressor_id) {
     compressor_iterator iterator = compressors_.find(compressor_id);
     PP_DCHECK(iterator != compressors_.end());
 
@@ -439,16 +430,14 @@
     iterator->second->ReadFileChunkDone(var_dict);
   }
 
-  void WriteChunkDone(const pp::VarDictionary& var_dict,
-                      int compressor_id) {
+  void WriteChunkDone(const pp::VarDictionary& var_dict, int compressor_id) {
     compressor_iterator iterator = compressors_.find(compressor_id);
     PP_DCHECK(iterator != compressors_.end());
 
     iterator->second->WriteChunkDone(var_dict);
   }
 
-  void CloseArchive(const pp::VarDictionary& var_dict,
-                    int compressor_id) {
+  void CloseArchive(const pp::VarDictionary& var_dict, int compressor_id) {
     compressor_iterator iterator = compressors_.find(compressor_id);
 
     if (iterator != compressors_.end())
diff --git a/ui/file_manager/zip_archiver/cpp/request.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/request.cc
similarity index 88%
rename from ui/file_manager/zip_archiver/cpp/request.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/request.cc
index e96a1e4..777df215 100644
--- a/ui/file_manager/zip_archiver/cpp/request.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/request.cc
@@ -99,9 +99,8 @@
   return request;
 }
 
-pp::VarDictionary request::CreateReadFileChunkRequest(
-    const int compressor_id,
-    const int64_t length) {
+pp::VarDictionary request::CreateReadFileChunkRequest(const int compressor_id,
+                                                      const int64_t length) {
   pp::VarDictionary request;
   request.Set(request::key::kOperation, READ_FILE_CHUNK);
   request.Set(request::key::kCompressorId, compressor_id);
@@ -156,13 +155,12 @@
   return request;
 }
 
-pp::VarDictionary request::CreateConsoleLog(
-    const std::string& file_system_id,
-    const std::string& request_id,
-    const std::string& src_file,
-    int src_line,
-    const std::string& src_func,
-    const std::string& message) {
+pp::VarDictionary request::CreateConsoleLog(const std::string& file_system_id,
+                                            const std::string& request_id,
+                                            const std::string& src_file,
+                                            int src_line,
+                                            const std::string& src_func,
+                                            const std::string& message) {
   pp::VarDictionary request =
       CreateBasicRequest(CONSOLE_LOG, file_system_id, request_id);
   request.Set(request::key::kSrcFile, src_file);
@@ -172,9 +170,8 @@
   return request;
 }
 
-pp::VarDictionary request::CreateCompressorError(
-    int compressor_id,
-    const std::string& error) {
+pp::VarDictionary request::CreateCompressorError(int compressor_id,
+                                                 const std::string& error) {
   pp::VarDictionary request;
   request.Set(request::key::kOperation, COMPRESSOR_ERROR);
   request.Set(request::key::kCompressorId, compressor_id);
diff --git a/ui/file_manager/zip_archiver/cpp/request.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/request.h
similarity index 69%
rename from ui/file_manager/zip_archiver/cpp/request.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/request.h
index a691b5f..2808ba58 100644
--- a/ui/file_manager/zip_archiver/cpp/request.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/request.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef REQUEST_H_
-#define REQUEST_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_REQUEST_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_REQUEST_H_
 
 #include "ppapi/cpp/var_array_buffer.h"
 #include "ppapi/cpp/var_dictionary.h"
@@ -25,9 +25,9 @@
 const char kMetadata[] = "metadata";  // Should be a pp:VarDictionary.
 const char kArchiveSize[] =
     "archive_size";  // Should be a string as int64_t is not support by pp::Var.
-const char kIndex[] = "index";         // Should be a string as int64_t is not
-                                       // supported by pp::Var.
-const char kEncoding[] = "encoding";   // Should be a string.
+const char kIndex[] = "index";        // Should be a string as int64_t is not
+                                      // supported by pp::Var.
+const char kEncoding[] = "encoding";  // Should be a string.
 const char kOpenRequestId[] = "open_request_id";  // Should be a string, just
                                                   // like kRequestId.
 const char kReadFileData[] = "read_file_data";    // Should be a
@@ -36,28 +36,28 @@
 const char kPassphrase[] = "passphrase";          // Should be a string.
 
 // Mandatory keys for all packing requests.
-const char kCompressorId[] = "compressor_id";         // Should be an int.
+const char kCompressorId[] = "compressor_id";  // Should be an int.
 
 // Optional keys unique to packing operations.
-const char kEntryId[] = "entry_id";                   // Should be an int.
-const char kPathname[] = "pathname";                  // Should be a string.
-const char kFileSize[] = "file_size";                 // Should be a string.
-const char kIsDirectory[] = "is_directory";           // Should be a bool.
-const char kModificationTime[] = "modification_time"; // Should be a string
-                                                      // (mm/dd/yy h:m:s).
-const char kHasError[] = "has_error";                 // Should be a bool.
+const char kEntryId[] = "entry_id";                    // Should be an int.
+const char kPathname[] = "pathname";                   // Should be a string.
+const char kFileSize[] = "file_size";                  // Should be a string.
+const char kIsDirectory[] = "is_directory";            // Should be a bool.
+const char kModificationTime[] = "modification_time";  // Should be a string
+                                                       // (mm/dd/yy h:m:s).
+const char kHasError[] = "has_error";                  // Should be a bool.
 
 // Optional keys used for both packing and unpacking operations.
-const char kError[] = "error";        // Should be a string.
+const char kError[] = "error";               // Should be a string.
 const char kChunkBuffer[] = "chunk_buffer";  // Should be a pp::VarArrayBuffer.
-const char kOffset[] = "offset";       // Should be a string as int64_t is not
-                                       // supported by pp::Var.
-const char kLength[] = "length";       // Should be a string as int64_t is not
-                                       // supported by pp::Var.
-const char kSrcFile[] = "src_file";               // Should be a string.
-const char kSrcLine[] = "src_line";               // Should be a string.
-const char kSrcFunc[] = "src_func";               // Should be a string.
-const char kMessage[] = "message";                // Should be a string.
+const char kOffset[] = "offset";     // Should be a string as int64_t is not
+                                     // supported by pp::Var.
+const char kLength[] = "length";     // Should be a string as int64_t is not
+                                     // supported by pp::Var.
+const char kSrcFile[] = "src_file";  // Should be a string.
+const char kSrcLine[] = "src_line";  // Should be a string.
+const char kSrcFunc[] = "src_func";  // Should be a string.
+const char kMessage[] = "message";   // Should be a string.
 }  // namespace key
 
 // Defines request operations. These operations should be the same as the
@@ -135,13 +135,13 @@
 
 pp::VarDictionary CreateCreateArchiveDoneResponse(int compressor_id);
 
-pp::VarDictionary CreateReadFileChunkRequest(int compressor_id,
-                                             int64_t length);
+pp::VarDictionary CreateReadFileChunkRequest(int compressor_id, int64_t length);
 
-pp::VarDictionary CreateWriteChunkRequest(int compressor_id,
-                                          const pp::VarArrayBuffer& array_buffer,
-                                          int64_t offset,
-                                          int64_t length);
+pp::VarDictionary CreateWriteChunkRequest(
+    int compressor_id,
+    const pp::VarArrayBuffer& array_buffer,
+    int64_t offset,
+    int64_t length);
 
 pp::VarDictionary CreateAddToArchiveDoneResponse(int compressor_id);
 
@@ -152,13 +152,12 @@
                                         const std::string& request_id,
                                         const std::string& error);
 
-pp::VarDictionary CreateConsoleLog(
-    const std::string& file_system_id,
-    const std::string& request_id,
-    const std::string& src_file,
-    int src_line,
-    const std::string& src_func,
-    const std::string& message);
+pp::VarDictionary CreateConsoleLog(const std::string& file_system_id,
+                                   const std::string& request_id,
+                                   const std::string& src_file,
+                                   int src_line,
+                                   const std::string& src_func,
+                                   const std::string& message);
 
 // Creates a compressor error.
 pp::VarDictionary CreateCompressorError(int compressor_id,
@@ -171,4 +170,4 @@
 
 }  // namespace request
 
-#endif  // REQUEST_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_REQUEST_H_
diff --git a/ui/file_manager/zip_archiver/cpp/volume.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc
similarity index 83%
rename from ui/file_manager/zip_archiver/cpp/volume.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc
index d881f1c..4a76522 100644
--- a/ui/file_manager/zip_archiver/cpp/volume.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc
@@ -13,10 +13,10 @@
 
 namespace {
 
-#define LOG(x) \
-  do { \
-    std::stringstream fmt; \
-    fmt << x; \
+#define LOG(x)                                                            \
+  do {                                                                    \
+    std::stringstream fmt;                                                \
+    fmt << x;                                                             \
     message_sender_->CONSOLE_LOG(file_system_id_, request_id, fmt.str()); \
   } while (0)
 
@@ -101,12 +101,8 @@
     std::string entry_path_without_next_parent = entry_path.substr(
         position + sizeof(kPathDelimiter) - 1 /* Last char is '\0'. */);
 
-    ConstructMetadata(index,
-                      entry_path_without_next_parent,
-                      size,
-                      is_directory,
-                      modification_time,
-                      &entry_metadata);
+    ConstructMetadata(index, entry_path_without_next_parent, size, is_directory,
+                      modification_time, &entry_metadata);
   }
 
   // Recreate parent_metadata. This is necessary because pp::VarDictionary::Get
@@ -131,8 +127,8 @@
   }
 
   virtual void RequestPassphrase(const std::string& request_id) {
-    volume_->message_sender()->SendPassphraseRequest(
-        volume_->file_system_id(), request_id);
+    volume_->message_sender()->SendPassphraseRequest(volume_->file_system_id(),
+                                                     request_id);
   }
 
  private:
@@ -169,10 +165,11 @@
   OpenFileArgs(const std::string& request_id,
                int64_t index,
                const std::string& encoding,
-               int64_t archive_size) : request_id(request_id),
-                                       index(index),
-                                       encoding(encoding),
-                                       archive_size(archive_size) {}
+               int64_t archive_size)
+      : request_id(request_id),
+        index(index),
+        encoding(encoding),
+        archive_size(archive_size) {}
   const std::string request_id;
   const int64_t index;
   const std::string encoding;
@@ -237,8 +234,8 @@
                       const std::string& encoding,
                       int64_t archive_size) {
   worker_.message_loop().PostWork(callback_factory_.NewCallback(
-      &Volume::OpenFileCallback, OpenFileArgs(request_id, index, encoding,
-      archive_size)));
+      &Volume::OpenFileCallback,
+      OpenFileArgs(request_id, index, encoding, archive_size)));
 }
 
 void Volume::CloseFile(const std::string& request_id,
@@ -262,8 +259,8 @@
 
   job_lock_.Acquire();
   if (request_id == reader_request_id_) {
-    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())->
-        SetBufferAndSignal(array_buffer, read_offset);
+    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())
+        ->SetBufferAndSignal(array_buffer, read_offset);
   }
   job_lock_.Release();
 }
@@ -272,8 +269,8 @@
   PP_DCHECK(volume_archive_);
   job_lock_.Acquire();
   if (request_id == reader_request_id_) {
-    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())->
-        ReadErrorSignal();
+    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())
+        ->ReadErrorSignal();
   }
   job_lock_.Release();
 }
@@ -284,8 +281,8 @@
 
   job_lock_.Acquire();
   if (request_id == reader_request_id_) {
-    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())->
-        SetPassphraseAndSignal(passphrase);
+    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())
+        ->SetPassphraseAndSignal(passphrase);
   }
   job_lock_.Release();
 }
@@ -295,8 +292,8 @@
 
   job_lock_.Acquire();
   if (request_id == reader_request_id_) {
-    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())->
-        PassphraseErrorSignal();
+    static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())
+        ->PassphraseErrorSignal();
   }
   job_lock_.Release();
 }
@@ -306,21 +303,21 @@
                                   const std::string& encoding,
                                   int64_t archive_size) {
   if (volume_archive_) {
-     message_sender_->SendFileSystemError(
-         file_system_id_, request_id, "ALREADY_OPENED");
+    message_sender_->SendFileSystemError(file_system_id_, request_id,
+                                         "ALREADY_OPENED");
   }
 
   job_lock_.Acquire();
   volume_archive_ = volume_archive_factory_->Create(
       volume_reader_factory_->Create(archive_size));
-  static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())->
-      SetRequestId(request_id);
+  static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())
+      ->SetRequestId(request_id);
   reader_request_id_ = request_id;
   job_lock_.Release();
 
   if (!volume_archive_->Init(encoding)) {
-    message_sender_->SendFileSystemError(
-        file_system_id_, request_id, volume_archive_->error_message());
+    message_sender_->SendFileSystemError(file_system_id_, request_id,
+                                         volume_archive_->error_message());
     ClearJob();
     delete volume_archive_;
     volume_archive_ = nullptr;
@@ -338,11 +335,9 @@
 
   for (;;) {
     path_name.clear();
-    if (volume_archive_->GetCurrentFileInfo(
-        &path_name,
-        &size,
-        &is_directory,
-        &modification_time) == VolumeArchive::RESULT_FAIL) {
+    if (volume_archive_->GetCurrentFileInfo(&path_name, &size, &is_directory,
+                                            &modification_time) ==
+        VolumeArchive::RESULT_FAIL) {
       message_sender_->SendFileSystemError(file_system_id_, request_id,
                                            volume_archive_->error_message());
       ClearJob();
@@ -381,20 +376,19 @@
                                         root_metadata);
 }
 
-void Volume::OpenFileCallback(int32_t /*result*/,
-                              const OpenFileArgs& args) {
+void Volume::OpenFileCallback(int32_t /*result*/, const OpenFileArgs& args) {
   if (!volume_archive_) {
-     message_sender_->SendFileSystemError(
-         file_system_id_, args.request_id, "NOT_OPENED");
-     return;
+    message_sender_->SendFileSystemError(file_system_id_, args.request_id,
+                                         "NOT_OPENED");
+    return;
   }
 
   job_lock_.Acquire();
   if (!reader_request_id_.empty()) {
     // It is illegal to open a file while another operation is in progress or
     // another file is opened.
-    message_sender_->SendFileSystemError(
-        file_system_id_, args.request_id, "ILLEGAL");
+    message_sender_->SendFileSystemError(file_system_id_, args.request_id,
+                                         "ILLEGAL");
     job_lock_.Release();
     return;
   }
@@ -416,11 +410,9 @@
     return;
   }
 
-  if (volume_archive_->GetCurrentFileInfo(
-      &path_name,
-      &size,
-      &is_directory,
-      &modification_time) != VolumeArchive::RESULT_SUCCESS) {
+  if (volume_archive_->GetCurrentFileInfo(&path_name, &size, &is_directory,
+                                          &modification_time) !=
+      VolumeArchive::RESULT_SUCCESS) {
     message_sender_->SendFileSystemError(file_system_id_, args.request_id,
                                          volume_archive_->error_message());
     ClearJob();
@@ -438,17 +430,17 @@
   reader_request_id_ = "";
   job_lock_.Release();
 
-  message_sender_->SendCloseFileDone(
-      file_system_id_, request_id, open_request_id);
+  message_sender_->SendCloseFileDone(file_system_id_, request_id,
+                                     open_request_id);
 }
 
 void Volume::ReadFileCallback(int32_t /*result*/,
                               const std::string& request_id,
                               const pp::VarDictionary& dictionary) {
   if (!volume_archive_) {
-     message_sender_->SendFileSystemError(
-         file_system_id_, request_id, "NOT_OPENED");
-     return;
+    message_sender_->SendFileSystemError(file_system_id_, request_id,
+                                         "NOT_OPENED");
+    return;
   }
 
   std::string open_request_id(
@@ -462,8 +454,8 @@
   job_lock_.Acquire();
   if (open_request_id != reader_request_id_) {
     // The file is not opened.
-    message_sender_->SendFileSystemError(
-        file_system_id_, request_id, "FILE_NOT_OPENED");
+    message_sender_->SendFileSystemError(file_system_id_, request_id,
+                                         "FILE_NOT_OPENED");
     job_lock_.Release();
     return;
   }
@@ -474,15 +466,15 @@
   int64_t left_length = length;
   while (left_length > 0) {
     const char* destination_buffer = nullptr;
-    int64_t read_bytes = volume_archive_->ReadData(
-        offset, left_length, &destination_buffer);
+    int64_t read_bytes =
+        volume_archive_->ReadData(offset, left_length, &destination_buffer);
 
     if (read_bytes < 0) {
       // Error messages should be sent to the read request (request_id), not
       // open request (open_request_id), as the last one has finished and this
       // is a read file.
-      message_sender_->SendFileSystemError(
-          file_system_id_, request_id, volume_archive_->error_message());
+      message_sender_->SendFileSystemError(file_system_id_, request_id,
+                                           volume_archive_->error_message());
 
       // Should not cleanup VolumeArchive as Volume::CloseFile will be called in
       // case of failure.
@@ -498,8 +490,8 @@
     }
 
     bool has_more_data = left_length - read_bytes > 0 && read_bytes > 0;
-    message_sender_->SendReadFileDone(
-        file_system_id_, request_id, array_buffer, has_more_data);
+    message_sender_->SendReadFileDone(file_system_id_, request_id, array_buffer,
+                                      has_more_data);
 
     if (read_bytes == 0)
       break;  // No more available data.
@@ -510,7 +502,6 @@
   volume_archive_->MaybeDecompressAhead();
 }
 
-
 void Volume::ClearJob() {
   job_lock_.Acquire();
   reader_request_id_ = "";
diff --git a/ui/file_manager/zip_archiver/cpp/volume.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.h
similarity index 96%
rename from ui/file_manager/zip_archiver/cpp/volume.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume.h
index 1bd89531..445c523 100644
--- a/ui/file_manager/zip_archiver/cpp/volume.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.h
@@ -2,20 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef VOLUME_H_
-#define VOLUME_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_H_
 
 #include <pthread.h>
 
+#include "javascript_message_sender_interface.h"
+#include "javascript_requestor_interface.h"
 #include "ppapi/cpp/instance_handle.h"
 #include "ppapi/cpp/var_array_buffer.h"
 #include "ppapi/cpp/var_dictionary.h"
 #include "ppapi/utility/completion_callback_factory.h"
 #include "ppapi/utility/threading/lock.h"
 #include "ppapi/utility/threading/simple_thread.h"
-
-#include "javascript_requestor_interface.h"
-#include "javascript_message_sender_interface.h"
 #include "volume_archive.h"
 
 // A factory that creates VolumeArchive(s). Useful for testing.
@@ -116,8 +115,7 @@
                             int64_t archive_size);
 
   // A calback helper for OpenFile.
-  void OpenFileCallback(int32_t result,
-                        const OpenFileArgs& args);
+  void OpenFileCallback(int32_t result, const OpenFileArgs& args);
 
   // A callback helper for CloseFile.
   void CloseFileCallback(int32_t result,
@@ -188,4 +186,4 @@
   std::map<int, std::string> index_to_pathname_;
 };
 
-#endif  /// VOLUME_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_H_
diff --git a/ui/file_manager/zip_archiver/cpp/volume_archive.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h
similarity index 89%
rename from ui/file_manager/zip_archiver/cpp/volume_archive.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h
index e5015fb..6e5fdd6 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_archive.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef VOLUME_ARCHIVE_H_
-#define VOLUME_ARCHIVE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_H_
 
 #include <string>
 
@@ -31,8 +31,8 @@
   // archive file.
   virtual bool Init(const std::string& encoding) = 0;
 
-  // Gets the next header. If path_name is set to nullptr, then there are no more
-  // available headers. Returns true if reading next header was successful.
+  // Gets the next header. If path_name is set to nullptr, then there are no
+  // more available headers. Returns true if reading next header was successful.
   // In case of failure the error message can be obtained with
   // VolumeArchive::error_message().
   virtual VolumeArchive::Result GetCurrentFileInfo(
@@ -98,8 +98,8 @@
   }
 
  private:
-  VolumeReader* reader_;    // The reader that actually reads the archive data.
+  VolumeReader* reader_;  // The reader that actually reads the archive data.
   std::string error_message_;  // An error message set in case of any errors.
 };
 
-#endif  // VOLUME_ARCHIVE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_H_
diff --git a/ui/file_manager/zip_archiver/cpp/volume_archive_minizip.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc
similarity index 86%
rename from ui/file_manager/zip_archiver/cpp/volume_archive_minizip.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc
index 8e2a488c..79812b0 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_archive_minizip.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc
@@ -4,11 +4,11 @@
 
 #include "volume_archive_minizip.h"
 
+#include <time.h>
 #include <algorithm>
 #include <cerrno>
 #include <cstring>
 #include <limits>
-#include <time.h>
 
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
@@ -37,8 +37,8 @@
   const void* destination_buffer;
 
   do {
-    int64_t read_bytes = archive->reader()->Read(left_length,
-                                                 &destination_buffer);
+    int64_t read_bytes =
+        archive->reader()->Read(left_length, &destination_buffer);
     // End of the zip file.
     if (read_bytes == 0)
       break;
@@ -50,7 +50,7 @@
   } while (left_length > 0);
 
   if (archive->reader()->Seek(static_cast<int64_t>(offset),
-                         ZLIB_FILEFUNC_SEEK_SET) < 0) {
+                              ZLIB_FILEFUNC_SEEK_SET) < 0) {
     return -1 /* Error */;
   }
   archive->dynamic_cache_size_ = bytes_to_read - left_length;
@@ -59,10 +59,10 @@
   return unzip_size - left_length;
 }
 
-uLong CustomArchiveRead(void* archive,
-                        void* /* stream */,
-                        void* buffer,
-                        uLong size) {
+uint32_t CustomArchiveRead(void* archive,
+                           void* /* stream */,
+                           void* buffer,
+                           uint32_t size) {
   VolumeArchiveMinizip* archive_minizip =
       static_cast<VolumeArchiveMinizip*>(archive);
   int64_t offset = archive_minizip->reader()->offset();
@@ -89,19 +89,17 @@
     if (archive_minizip->dynamic_cache_size_ == 0 ||
         offset < archive_minizip->dynamic_cache_offset_ ||
         archive_minizip->dynamic_cache_offset_ +
-        archive_minizip->dynamic_cache_size_ <
-        offset + size) {
+                archive_minizip->dynamic_cache_size_ <
+            offset + size) {
       volume_archive_functions::DynamicCache(archive_minizip, size);
     }
 
     // Just copy the required data from the cache.
     int64_t offset_in_cache = offset - archive_minizip->dynamic_cache_offset_;
-    int64_t copy_length =
-        std::min(left_length,
-                 archive_minizip->dynamic_cache_size_ - offset_in_cache);
+    int64_t copy_length = std::min(
+        left_length, archive_minizip->dynamic_cache_size_ - offset_in_cache);
     memcpy(unzip_buffer_pointer,
-           archive_minizip->dynamic_cache_ + offset_in_cache,
-           copy_length);
+           archive_minizip->dynamic_cache_ + offset_in_cache, copy_length);
     unzip_buffer_pointer += copy_length;
     left_length -= copy_length;
     if (archive_minizip->reader()->Seek(static_cast<int64_t>(copy_length),
@@ -113,10 +111,10 @@
   return size;
 }
 
-uLong CustomArchiveWrite(void* /*archive*/,
-                         void* /*stream*/,
-                         const void* /*buffer*/,
-                         uLong /*length*/) {
+uint32_t CustomArchiveWrite(void* /*archive*/,
+                            void* /*stream*/,
+                            const void* /*buffer*/,
+                            uint32_t /*length*/) {
   return 0 /* Success */;
 }
 
@@ -128,7 +126,7 @@
 
 long CustomArchiveSeek(void* archive,
                        void* /*stream*/,
-                       uLong offset,
+                       uint32_t offset,
                        int origin) {
   VolumeArchiveMinizip* archive_minizip =
       static_cast<VolumeArchiveMinizip*>(archive);
@@ -153,7 +151,7 @@
   return password;
 }
 
-}  // volume_archive_functions
+}  // namespace volume_archive_functions
 
 VolumeArchiveMinizip::VolumeArchiveMinizip(VolumeReader* reader)
     : VolumeArchive(reader),
@@ -187,9 +185,8 @@
 
   // Load maximum static_cache_size_ bytes from the end of the archive to
   // static_cache_.
-  static_cache_size_ =
-      std::min(volume_archive_constants::kStaticCacheSize,
-               reader()->archive_size());
+  static_cache_size_ = std::min(volume_archive_constants::kStaticCacheSize,
+                                reader()->archive_size());
   int64_t previous_offset = reader()->offset();
   char* buffer_pointer = static_cache_;
   int64_t left_length = static_cache_size_;
@@ -227,7 +224,6 @@
     int64_t* size,
     bool* is_directory,
     time_t* modification_time) {
-
   // Headers are being read from the central directory (in the ZIP format), so
   // use a large block size to save on IPC calls. The headers in EOCD are
   // grouped one by one.
@@ -246,14 +242,13 @@
   // Get the information of the opened file.
   unz_file_info raw_file_info = {};
   char raw_file_name_in_zip[volume_archive_constants::kZipMaxPath] = {};
-  const int result = unzGetCurrentFileInfo(zip_file_,
-                                           &raw_file_info,
-                                           raw_file_name_in_zip,
-                                           sizeof(raw_file_name_in_zip) - 1,
-                                           nullptr,  // extraField.
-                                           0,     // extraFieldBufferSize.
-                                           nullptr,  // szComment.
-                                           0);    // commentBufferSize.
+  const int result =
+      unzGetCurrentFileInfo(zip_file_, &raw_file_info, raw_file_name_in_zip,
+                            sizeof(raw_file_name_in_zip) - 1,
+                            nullptr,  // extraField.
+                            0,        // extraFieldBufferSize.
+                            nullptr,  // szComment.
+                            0);       // commentBufferSize.
 
   if (result != UNZ_OK || raw_file_name_in_zip[0] == '\0') {
     set_error_message(volume_archive_constants::kArchiveNextHeaderError);
@@ -269,14 +264,15 @@
   // Construct the last modified time. The timezone info is not present in
   // zip files. By default, the time is set as local time in zip format.
   base::Time::Exploded exploded_time = {};  // Zero-clear.
-  exploded_time.year = raw_file_info.tmu_date.tm_year;
+  // exploded_time.year = raw_file_info.tmu_date.tm_year;
   // The month in zip file is 0-based, whereas ours is 1-based.
-  exploded_time.month = raw_file_info.tmu_date.tm_mon + 1;
-  exploded_time.day_of_month = raw_file_info.tmu_date.tm_mday;
-  exploded_time.hour = raw_file_info.tmu_date.tm_hour;
-  exploded_time.minute = raw_file_info.tmu_date.tm_min;
-  exploded_time.second = raw_file_info.tmu_date.tm_sec;
-  exploded_time.millisecond = 0;
+  // TODO(yawano): fix this.
+  // exploded_time.month = raw_file_info.tmu_date.tm_mon + 1;
+  // exploded_time.day_of_month = raw_file_info.tmu_date.tm_mday;
+  // exploded_time.hour = raw_file_info.tmu_date.tm_hour;
+  // exploded_time.minute = raw_file_info.tmu_date.tm_min;
+  // exploded_time.second = raw_file_info.tmu_date.tm_sec;
+  // exploded_time.millisecond = 0;
 
   base::Time local_time;
   // If the modification time is not available, we set the value to the current
@@ -305,21 +301,20 @@
   last_read_data_offset_ = 0;
   decompressed_data_size_ = 0;
 
-  const int kDefaultCaseSensivityOfOS = 0;
-  if (unzLocateFile(zip_file_, path_name.c_str(), kDefaultCaseSensivityOfOS) !=
-      UNZ_OK) {
+  // Setting nullptr to filename_compare_func falls back to strcmp, i.e. case
+  // sensitive.
+  if (unzLocateFile(zip_file_, path_name.c_str(),
+                    nullptr /* filename_compare_func */) != UNZ_OK) {
     set_error_message(volume_archive_constants::kArchiveNextHeaderError);
     return false;
   }
 
   unz_file_info raw_file_info = {};
   char raw_file_name_in_zip[volume_archive_constants::kZipMaxPath] = {};
-  if (unzGetCurrentFileInfo(zip_file_,
-                            &raw_file_info,
-                            raw_file_name_in_zip,
+  if (unzGetCurrentFileInfo(zip_file_, &raw_file_info, raw_file_name_in_zip,
                             sizeof(raw_file_name_in_zip) - 1,
                             nullptr,  // extraField.
-                            0,     // extraFieldBufferSize.
+                            0,        // extraFieldBufferSize.
                             nullptr,  // szComment.
                             0) != UNZ_OK) {
     set_error_message(volume_archive_constants::kArchiveNextHeaderError);
@@ -420,8 +415,7 @@
     // volume_archive_constants::kMinimumDataChunkSize (see left_length
     // initialization), which is positive and less than size_t maximum.
     // So conversion from int64_t to size_t is safe here.
-    size = unzReadCurrentFile(zip_file_,
-                              decompressed_data_buffer_ + bytes_read,
+    size = unzReadCurrentFile(zip_file_, decompressed_data_buffer_ + bytes_read,
                               left_length);
     if (size < 0) {  // Error.
       set_error_message(volume_archive_constants::kArchiveReadDataError);
@@ -456,9 +450,9 @@
 }
 
 int64_t VolumeArchiveMinizip::ReadData(int64_t offset,
-                                          int64_t length,
-                                          const char** buffer) {
-  PP_DCHECK(length > 0);              // Length must be at least 1.
+                                       int64_t length,
+                                       const char** buffer) {
+  PP_DCHECK(length > 0);  // Length must be at least 1.
   // In case of first read or no more available data in the internal buffer or
   // offset is different from the last_read_data_offset_, then force
   // VolumeArchiveMinizip::DecompressData as the decompressed data is
diff --git a/ui/file_manager/zip_archiver/cpp/volume_archive_minizip.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h
similarity index 80%
rename from ui/file_manager/zip_archiver/cpp/volume_archive_minizip.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h
index 8c02438..621898d 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_archive_minizip.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef VOLUME_ARCHIVE_MINIZIP_H_
-#define VOLUME_ARCHIVE_MINIZIP_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_MINIZIP_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_MINIZIP_H_
 
 #include <string>
 
-#include "third_party/zlib/contrib/minizip/unzip.h"
-#include "third_party/zlib/contrib/minizip/zip.h"
+#include "third_party/minizip/src/unzip.h"
+#include "third_party/minizip/src/zip.h"
 
 #include "volume_archive.h"
 
@@ -54,21 +54,23 @@
 // A namespace with custom functions passed to minizip.
 namespace volume_archive_functions {
 
-  int64_t DynamicCache(VolumeArchiveMinizip* archive, int64_t unz_size);
+int64_t DynamicCache(VolumeArchiveMinizip* archive, int64_t unz_size);
 
-  uLong CustomArchiveRead(void* archive, void* stream, void* buf, uLong size);
+uint32_t CustomArchiveRead(void* archive,
+                           void* stream,
+                           void* buf,
+                           uint32_t size);
 
-  // Returns the offset from the beginning of the data.
-  long CustomArchiveTell(void* archive, void* stream);
+// Returns the offset from the beginning of the data.
+long CustomArchiveTell(void* archive, void* stream);
 
-  // Moves the current offset to the specified position.
-  long CustomArchiveSeek(void* archive,
-                         void* stream,
-                         uLong offset,
-                         int origin);
+// Moves the current offset to the specified position.
+long CustomArchiveSeek(void* archive,
+                       void* stream,
+                       uint32_t offset,
+                       int origin);
 
-}  // compressor_archive_functions
-
+}  // namespace volume_archive_functions
 
 class VolumeArchiveMinizip;
 
@@ -108,16 +110,21 @@
   // Custom functions need to access private variables of
   // CompressorArchiveMinizip frequently.
   friend int64_t volume_archive_functions::DynamicCache(
-      VolumeArchiveMinizip* va, int64_t unz_size);
+      VolumeArchiveMinizip* va,
+      int64_t unz_size);
 
-  friend uLong volume_archive_functions::CustomArchiveRead(
-      void* archive, void* stream, void* buf, uLong size);
+  friend uint32_t volume_archive_functions::CustomArchiveRead(void* archive,
+                                                              void* stream,
+                                                              void* buf,
+                                                              uint32_t size);
 
-  friend long volume_archive_functions::CustomArchiveTell(
-      void* archive, void* stream);
+  friend long volume_archive_functions::CustomArchiveTell(void* archive,
+                                                          void* stream);
 
-  friend long volume_archive_functions::CustomArchiveSeek(
-      void* archive, void* stream, uLong offset, int origin);
+  friend long volume_archive_functions::CustomArchiveSeek(void* archive,
+                                                          void* stream,
+                                                          uint32_t offset,
+                                                          int origin);
 
  private:
   // Decompress length bytes of data starting from offset.
@@ -205,4 +212,4 @@
   bool decompressed_error_;
 };
 
-#endif  // VOLUME_ARCHIVE_MINIZIP_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_ARCHIVE_MINIZIP_H_
diff --git a/ui/file_manager/zip_archiver/cpp/volume_reader.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader.h
similarity index 85%
rename from ui/file_manager/zip_archiver/cpp/volume_reader.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader.h
index 58cf1c3..484f8ce 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_reader.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef VOLUME_READER_H_
-#define VOLUME_READER_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_H_
 
 #include <string>
 
@@ -39,4 +39,4 @@
   virtual int64_t archive_size() = 0;
 };
 
-#endif  // VOLUME_READER_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_H_
diff --git a/ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.cc
similarity index 96%
rename from ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.cc
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.cc
index 48234c1..dc852553d 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.cc
@@ -7,9 +7,8 @@
 #include <algorithm>
 #include <limits>
 
-#include "third_party/zlib/contrib/minizip/unzip.h"
-
 #include "ppapi/cpp/logging.h"
+#include "third_party/minizip/src/unzip.h"
 
 VolumeReaderJavaScriptStream::VolumeReaderJavaScriptStream(
     int64_t archive_size,
@@ -20,9 +19,9 @@
       read_error_(false),
       passphrase_error_(false),
       offset_(0),
-      last_read_chunk_offset_(-1) /* For first call -1 will force a chunk
-                                     request from JavaScript as offset
-                                     parameter is 0. */,
+      // For first call -1 will force a chunk request from JavaScript as offset
+      // parameter is 0.
+      last_read_chunk_offset_(-1),
       read_ahead_array_buffer_ptr_(&first_array_buffer_) {
   pthread_mutex_init(&shared_state_lock_, nullptr);
   pthread_cond_init(&available_data_cond_, nullptr);
@@ -46,7 +45,7 @@
     first_array_buffer_.Unmap();
   else
     second_array_buffer_.Unmap();
-};
+}
 
 void VolumeReaderJavaScriptStream::SetBufferAndSignal(
     const pp::VarArrayBuffer& array_buffer,
diff --git a/ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.h
similarity index 94%
rename from ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.h
rename to chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.h
index b0632ed..c91405e 100644
--- a/ui/file_manager/zip_archiver/cpp/volume_reader_javascript_stream.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_reader_javascript_stream.h
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef VOLUME_READER_JAVSCRIPT_STREAM_H_
-#define VOLUME_READER_JAVSCRIPT_STREAM_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_JAVASCRIPT_STREAM_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_JAVASCRIPT_STREAM_H_
 
 #include <pthread.h>
 
-#include "ppapi/cpp/var_array_buffer.h"
-
 #include "javascript_requestor_interface.h"
+#include "ppapi/cpp/var_array_buffer.h"
 #include "volume_reader.h"
 
 // A VolumeReader that reads the content of the volume's archive from
@@ -117,4 +116,4 @@
   pp::VarArrayBuffer* read_ahead_array_buffer_ptr_;
 };
 
-#endif  // VOLUME_READER_JAVSCRIPT_STREAM_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_CPP_VOLUME_READER_JAVASCRIPT_STREAM_H_
diff --git a/ui/file_manager/zip_archiver/css/passphrase-dialog.css b/chrome/browser/resources/chromeos/zip_archiver/css/passphrase-dialog.css
similarity index 61%
rename from ui/file_manager/zip_archiver/css/passphrase-dialog.css
rename to chrome/browser/resources/chromeos/zip_archiver/css/passphrase-dialog.css
index f6e2cc1..da779be 100644
--- a/ui/file_manager/zip_archiver/css/passphrase-dialog.css
+++ b/chrome/browser/resources/chromeos/zip_archiver/css/passphrase-dialog.css
@@ -1,4 +1,10 @@
-input, paper-button, paper-checkbox {
+/* 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. */
+
+input,
+paper-button,
+paper-checkbox {
   -webkit-app-region: no-drag;
 }
 
@@ -26,7 +32,7 @@
 }
 
 #acceptButton {
-  color: #2196f3;
+  color: rgb(33, 150, 243);
 }
 
 #cancelButton {
diff --git a/chrome/browser/resources/chromeos/zip_archiver/css/passphrase.css b/chrome/browser/resources/chromeos/zip_archiver/css/passphrase.css
new file mode 100644
index 0000000..52928fd
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/css/passphrase.css
@@ -0,0 +1,17 @@
+/* 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 {
+  -webkit-app-region: drag;
+  bottom: 0;
+  left: 0;
+  padding: 15px 15px 8px 15px;
+  position: absolute;
+  right: 0;
+  top: 0;
+}
+
+#passphrase-dialog {
+  height: 100%;
+}
diff --git a/ui/file_manager/zip_archiver/externs_js/chrome.js b/chrome/browser/resources/chromeos/zip_archiver/externs_js/chrome.js
similarity index 100%
rename from ui/file_manager/zip_archiver/externs_js/chrome.js
rename to chrome/browser/resources/chromeos/zip_archiver/externs_js/chrome.js
diff --git a/ui/file_manager/zip_archiver/externs_js/polymer.js b/chrome/browser/resources/chromeos/zip_archiver/externs_js/polymer.js
similarity index 100%
rename from ui/file_manager/zip_archiver/externs_js/polymer.js
rename to chrome/browser/resources/chromeos/zip_archiver/externs_js/polymer.js
diff --git a/ui/file_manager/zip_archiver/gdb_script b/chrome/browser/resources/chromeos/zip_archiver/gdb_script
similarity index 100%
rename from ui/file_manager/zip_archiver/gdb_script
rename to chrome/browser/resources/chromeos/zip_archiver/gdb_script
diff --git a/ui/file_manager/zip_archiver/html/compressor.html b/chrome/browser/resources/chromeos/zip_archiver/html/compressor.html
similarity index 100%
rename from ui/file_manager/zip_archiver/html/compressor.html
rename to chrome/browser/resources/chromeos/zip_archiver/html/compressor.html
diff --git a/ui/file_manager/zip_archiver/html/passphrase-dialog.html b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
similarity index 64%
rename from ui/file_manager/zip_archiver/html/passphrase-dialog.html
rename to chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
index 0b0a82ca..2ffe146 100644
--- a/ui/file_manager/zip_archiver/html/passphrase-dialog.html
+++ b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase-dialog.html
@@ -1,15 +1,18 @@
-<link rel="import" href="../third-party/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html">
 
 <dom-module id="passphrase-dialog">
   <template>
     <link rel="stylesheet" href="../css/passphrase-dialog.css">
     <!-- TODO(takise): Translation -->
     <h3>This file is password protected</h3>
-    <paper-input-decorator>
+    <paper-input-container>
       <!-- TODO(takise): Translation -->
       Password
       <input is="core-input" type="password" id="input" autofocus>
-    </paper-input-decorator>
+    </paper-input-container>
     <div id="bar">
       <paper-checkbox id="remember">
         <!-- TODO(takise): Translation -->
@@ -21,7 +24,7 @@
             Cancel
         </paper-button>
         <paper-button on-click="accept" id="acceptButton">
-          <!-- TODO(takise): Translation --> 
+          <!-- TODO(takise): Translation -->
             Accept
         </paper-button>
       </div>
diff --git a/ui/file_manager/zip_archiver/html/passphrase.html b/chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html
similarity index 100%
rename from ui/file_manager/zip_archiver/html/passphrase.html
rename to chrome/browser/resources/chromeos/zip_archiver/html/passphrase.html
diff --git a/ui/file_manager/zip_archiver/icons/icon128.png b/chrome/browser/resources/chromeos/zip_archiver/icons/icon128.png
similarity index 100%
rename from ui/file_manager/zip_archiver/icons/icon128.png
rename to chrome/browser/resources/chromeos/zip_archiver/icons/icon128.png
Binary files differ
diff --git a/ui/file_manager/zip_archiver/icons/icon16.png b/chrome/browser/resources/chromeos/zip_archiver/icons/icon16.png
similarity index 100%
rename from ui/file_manager/zip_archiver/icons/icon16.png
rename to chrome/browser/resources/chromeos/zip_archiver/icons/icon16.png
Binary files differ
diff --git a/ui/file_manager/zip_archiver/icons/icon32.png b/chrome/browser/resources/chromeos/zip_archiver/icons/icon32.png
similarity index 100%
rename from ui/file_manager/zip_archiver/icons/icon32.png
rename to chrome/browser/resources/chromeos/zip_archiver/icons/icon32.png
Binary files differ
diff --git a/ui/file_manager/zip_archiver/icons/icon64.png b/chrome/browser/resources/chromeos/zip_archiver/icons/icon64.png
similarity index 100%
rename from ui/file_manager/zip_archiver/icons/icon64.png
rename to chrome/browser/resources/chromeos/zip_archiver/icons/icon64.png
Binary files differ
diff --git a/ui/file_manager/zip_archiver/icons/icon96.png b/chrome/browser/resources/chromeos/zip_archiver/icons/icon96.png
similarity index 100%
rename from ui/file_manager/zip_archiver/icons/icon96.png
rename to chrome/browser/resources/chromeos/zip_archiver/icons/icon96.png
Binary files differ
diff --git a/ui/file_manager/zip_archiver/js/app.js b/chrome/browser/resources/chromeos/zip_archiver/js/app.js
similarity index 70%
rename from ui/file_manager/zip_archiver/js/app.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/app.js
index 7c49d4c..51c28f0 100644
--- a/ui/file_manager/zip_archiver/js/app.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/app.js
@@ -29,11 +29,11 @@
 
   /**
    * The default filename for .nmf file.
-   * This value must not be const because it is overwritten in tests.
+   * This value must not be constant because it is overwritten in tests.
    * Since .nmf file is not available in .grd, we use .txt instead.
    * @type {string}
    */
-  DEFAULT_MODULE_NMF: 'module.nmf.txt',
+  DEFAULT_MODULE_NMF: 'module.nmf',
 
   /**
    * The default MIME type for .nmf file.
@@ -124,8 +124,8 @@
       return;
     }
 
-    volume.decompressor.processMessage(message.data, operation,
-                                       Number(requestId));
+    volume.decompressor.processMessage(
+        message.data, operation, Number(requestId));
   },
 
   /**
@@ -137,8 +137,9 @@
   handleMessage_: function(message) {
     // Get mandatory fields in a message.
     var operation = message.data[unpacker.request.Key.OPERATION];
-    console.assert(operation != undefined,  // Operation can be 0.
-                   'No NaCl operation: ' + operation + '.');
+    console.assert(
+        operation != undefined,  // Operation can be 0.
+        'No NaCl operation: ' + operation + '.');
 
     // Assign the message to either module.
     if (unpacker.request.isPackRequest(operation))
@@ -180,10 +181,11 @@
    */
   removeState_: function(fileSystemId) {
     chrome.storage.local.get([unpacker.app.STORAGE_KEY], function(result) {
-      console.assert(result[unpacker.app.STORAGE_KEY] &&
-                         result[unpacker.app.STORAGE_KEY][fileSystemId],
-                     'Should call removeState_ only for file systems that ',
-                     'have previously called saveState_.');
+      console.assert(
+          result[unpacker.app.STORAGE_KEY] &&
+              result[unpacker.app.STORAGE_KEY][fileSystemId],
+          'Should call removeState_ only for file systems that ',
+          'have previously called saveState_.');
 
       delete result[unpacker.app.STORAGE_KEY][fileSystemId];
       chrome.storage.local.set(result);
@@ -214,15 +216,13 @@
 
         chrome.fileSystem.restoreEntry(volumeState.entryId, function(entry) {
           if (chrome.runtime.lastError) {
-            console.error('Restore entry error for <', fileSystemId, '>: ' +
-                          chrome.runtime.lastError.message);
+            console.error(
+                'Restore entry error for <', fileSystemId,
+                '>: ' + chrome.runtime.lastError.message);
             reject('FAILED');
             return;
           }
-          fulfill({
-            entry: entry,
-            passphrase: volumeState.passphrase
-          });
+          fulfill({entry: entry, passphrase: volumeState.passphrase});
         });
       });
     });
@@ -241,45 +241,48 @@
    */
   loadVolume_: function(fileSystemId, entry, openedFiles, passphrase) {
     return new Promise(function(fulfill, reject) {
-      entry.file(function(file) {
-        // File is a Blob object, so it's ok to construct the Decompressor
-        // directly with it.
-        var passphraseManager = new unpacker.PassphraseManager(passphrase);
-        console.assert(unpacker.app.naclModule,
-                       'The NaCL module should have already been defined.');
-        var decompressor = new unpacker.Decompressor(
-            /** @type {!Object} */ (unpacker.app.naclModule),
-            fileSystemId, file, passphraseManager);
-        var volume = new unpacker.Volume(decompressor, entry);
+      entry.file(
+          function(file) {
+            // File is a Blob object, so it's ok to construct the Decompressor
+            // directly with it.
+            var passphraseManager = new unpacker.PassphraseManager(passphrase);
+            console.assert(
+                unpacker.app.naclModule,
+                'The NaCL module should have already been defined.');
+            var decompressor = new unpacker.Decompressor(
+                /** @type {!Object} */ (unpacker.app.naclModule), fileSystemId,
+                file, passphraseManager);
+            var volume = new unpacker.Volume(decompressor, entry);
 
-        var onLoadVolumeSuccess = function() {
-          if (Object.keys(openedFiles).length == 0) {
-            fulfill();
-            return;
-          }
+            var onLoadVolumeSuccess = function() {
+              if (Object.keys(openedFiles).length == 0) {
+                fulfill();
+                return;
+              }
 
-          // Restore opened files on NaCl side.
-          var openFilePromises = [];
-          for (var key in openedFiles) {
-            // 'key' is always a number but JS compiler complains that it is
-            // a string.
-            var openRequestId = Number(key);
-            var options =
-                /** @type {!unpacker.types.OpenFileRequestedOptions} */
-                (openedFiles[openRequestId]);
-            openFilePromises.push(new Promise(function(resolve, reject) {
-              volume.onOpenFileRequested(options, resolve, reject);
-            }));
-          }
+              // Restore opened files on NaCl side.
+              var openFilePromises = [];
+              for (var key in openedFiles) {
+                // 'key' is always a number but JS compiler complains that it is
+                // a string.
+                var openRequestId = Number(key);
+                var options =
+                    /** @type {!unpacker.types.OpenFileRequestedOptions} */
+                    (openedFiles[openRequestId]);
+                openFilePromises.push(new Promise(function(resolve, reject) {
+                  volume.onOpenFileRequested(options, resolve, reject);
+                }));
+              }
 
-          Promise.all(openFilePromises).then(fulfill, reject);
-        };
+              Promise.all(openFilePromises).then(fulfill, reject);
+            };
 
-        unpacker.app.volumes[fileSystemId] = volume;
-        volume.initialize(onLoadVolumeSuccess, reject);
-      }, function(error) {
-        reject('FAILED');
-      });
+            unpacker.app.volumes[fileSystemId] = volume;
+            volume.initialize(onLoadVolumeSuccess, reject);
+          },
+          function(error) {
+            reject('FAILED');
+          });
     });
   },
 
@@ -335,7 +338,9 @@
           // volume will be cleanup from both memory and local storage.
           // TODO(523195): Show a notification that the source file is gone.
           return unpacker.app.unmountVolume(fileSystemId, true)
-              .then(function() { return Promise.reject('FAILED'); });
+              .then(function() {
+                return Promise.reject('FAILED');
+              });
         });
   },
 
@@ -354,8 +359,8 @@
     unpacker.app.mountProcessCounter++;
     // Create a promise to load the NaCL module.
     if (!unpacker.app.moduleLoadedPromise)
-      unpacker.app.loadNaclModule(unpacker.app.DEFAULT_MODULE_NMF,
-                                  unpacker.app.DEFAULT_MODULE_TYPE);
+      unpacker.app.loadNaclModule(
+          unpacker.app.DEFAULT_MODULE_NMF, unpacker.app.DEFAULT_MODULE_TYPE);
 
     return unpacker.app.moduleLoadedPromise.then(function() {
       // In case there is no volume promise for fileSystemId then we
@@ -368,11 +373,13 @@
       }
 
       // Decrement the counter when the mounting process ends.
-      unpacker.app.volumeLoadedPromises[fileSystemId].then(function() {
-        unpacker.app.mountProcessCounter--;
-      }).catch(function(error) {
-        unpacker.app.mountProcessCounter--;
-      });
+      unpacker.app.volumeLoadedPromises[fileSystemId]
+          .then(function() {
+            unpacker.app.mountProcessCounter--;
+          })
+          .catch(function(error) {
+            unpacker.app.mountProcessCounter--;
+          });
 
       return unpacker.app.volumeLoadedPromises[fileSystemId];
     });
@@ -381,7 +388,9 @@
   /**
    * @return {boolean} True if NaCl module is loaded.
    */
-  naclModuleIsLoaded: function() { return !!unpacker.app.naclModule; },
+  naclModuleIsLoaded: function() {
+    return !!unpacker.app.naclModule;
+  },
 
   /**
    * Loads the NaCl module.
@@ -411,7 +420,7 @@
           unpacker.app.moduleLoadedPromise = null;
           return;
         }
-        unpacker.app.naclModule = document.getElementById(moduleId);
+        unpacker.app.naclModule = document.querySelector('#' + moduleId);
         fulfill();
       }, true);
 
@@ -504,22 +513,21 @@
   unmountVolume: function(fileSystemId, opt_forceUnmount) {
     return new Promise(function(fulfill, reject) {
       var volume = unpacker.app.volumes[fileSystemId];
-      console.assert(volume || opt_forceUnmount,
-                     'Unmount that is not forced must not be called for ',
-                     'volumes that are not restored.');
+      console.assert(
+          volume || opt_forceUnmount,
+          'Unmount that is not forced must not be called for ',
+          'volumes that are not restored.');
 
       if (!opt_forceUnmount && volume.inUse()) {
         reject('IN_USE');
         return;
       }
 
-      var options = {
-        fileSystemId: fileSystemId
-      };
+      var options = {fileSystemId: fileSystemId};
       chrome.fileSystemProvider.unmount(options, function() {
         if (chrome.runtime.lastError) {
-          console.error('Unmount error: ' + chrome.runtime.lastError.message +
-              '.');
+          console.error(
+              'Unmount error: ' + chrome.runtime.lastError.message + '.');
           reject('FAILED');
           return;
         }
@@ -647,55 +655,53 @@
 
     // Create a promise to load the NaCL module.
     if (!unpacker.app.moduleLoadedPromise) {
-      unpacker.app.loadNaclModule(unpacker.app.DEFAULT_MODULE_NMF,
-                                  unpacker.app.DEFAULT_MODULE_TYPE);
+      unpacker.app.loadNaclModule(
+          unpacker.app.DEFAULT_MODULE_NMF, unpacker.app.DEFAULT_MODULE_TYPE);
     }
 
-    unpacker.app.moduleLoadedPromise
-        .then(function() {
-          var compressor = new unpacker.Compressor(
-              /** @type {!Object} */ (unpacker.app.naclModule),
-             launchData.items);
+    unpacker.app.moduleLoadedPromise.then(function() {
+      var compressor = new unpacker.Compressor(
+          /** @type {!Object} */ (unpacker.app.naclModule), launchData.items);
 
-          var compressorId = compressor.getCompressorId();
+      var compressorId = compressor.getCompressorId();
 
-          unpacker.app.compressors[compressorId] = compressor;
+      unpacker.app.compressors[compressorId] = compressor;
 
-          // TODO(takise): Error messages have not been prepared yet for timer
-          // and error processing.
+      // TODO(takise): Error messages have not been prepared yet for timer
+      // and error processing.
 
-          // If packing takes significant amount of time, then show a
-          // notification about packing in progress.
-          // var deferredNotificationTimer = setTimeout(function() {
-          //   chrome.notifications.create(compressorId.toString(), {
-          //     type: 'basic',
-          //     iconUrl: chrome.runtime.getManifest().icons[128],
-          //     title: entry.name,
-          //     message: chrome.i18n.getMessage('packingMessage'),
-          //   }, function() {});
-          // }, unpacker.app.PACKING_NOTIFICATION_DELAY);
+      // If packing takes significant amount of time, then show a
+      // notification about packing in progress.
+      // var deferredNotificationTimer = setTimeout(function() {
+      //   chrome.notifications.create(compressorId.toString(), {
+      //     type: 'basic',
+      //     iconUrl: chrome.runtime.getManifest().icons[128],
+      //     title: entry.name,
+      //     message: chrome.i18n.getMessage('packingMessage'),
+      //   }, function() {});
+      // }, unpacker.app.PACKING_NOTIFICATION_DELAY);
 
-          var onError = function(compressorId) {
-            // clearTimeout(deferredNotificationTimer);
-            // console.error('Packing error: ' + error.message + '.');
-            // chrome.notifications.create(compressorId.toString(), {
-            //   type: 'basic',
-            //   iconUrl: chrome.runtime.getManifest().icons[128],
-            //   title: entry.name,
-            //   message: chrome.i18n.getMessage('packingErrorMessage')
-            // }, function() {});
-            unpacker.app.cleanupCompressor(compressorId, true /* hasError */);
-          };
+      var onError = function(compressorId) {
+        // clearTimeout(deferredNotificationTimer);
+        // console.error('Packing error: ' + error.message + '.');
+        // chrome.notifications.create(compressorId.toString(), {
+        //   type: 'basic',
+        //   iconUrl: chrome.runtime.getManifest().icons[128],
+        //   title: entry.name,
+        //   message: chrome.i18n.getMessage('packingErrorMessage')
+        // }, function() {});
+        unpacker.app.cleanupCompressor(compressorId, true /* hasError */);
+      };
 
-          var onSuccess = function(compressorId) {
-            // clearTimeout(deferredNotificationTimer);
-            // chrome.notifications.clear(compressorId.toString(),
-            //     function() {});
-            unpacker.app.cleanupCompressor(compressorId, false /* hasError */);
-          };
+      var onSuccess = function(compressorId) {
+        // clearTimeout(deferredNotificationTimer);
+        // chrome.notifications.clear(compressorId.toString(),
+        //     function() {});
+        unpacker.app.cleanupCompressor(compressorId, false /* hasError */);
+      };
 
-          compressor.compress(onSuccess, onError);
-        });
+      compressor.compress(onSuccess, onError);
+    });
   },
 
   /**
@@ -717,8 +723,8 @@
 
     // Create a promise to load the NaCL module.
     if (!unpacker.app.moduleLoadedPromise) {
-      unpacker.app.loadNaclModule(unpacker.app.DEFAULT_MODULE_NMF,
-                                  unpacker.app.DEFAULT_MODULE_TYPE);
+      unpacker.app.loadNaclModule(
+          unpacker.app.DEFAULT_MODULE_NMF, unpacker.app.DEFAULT_MODULE_TYPE);
     }
 
     unpacker.app.moduleLoadedPromise
@@ -726,87 +732,95 @@
           unpacker.app.mountProcessCounter--;
           launchData.items.forEach(function(item) {
             unpacker.app.mountProcessCounter++;
-            chrome.fileSystem.getDisplayPath(item.entry, function(
-                                                             entry,
-                                                             fileSystemId) {
-              // If loading takes significant amount of time, then show a
-              // notification about scanning in progress.
-              var deferredNotificationTimer = setTimeout(function() {
-                chrome.notifications.create(fileSystemId, {
-                  type: 'basic',
-                  iconUrl: chrome.runtime.getManifest().icons[128],
-                  title: entry.name,
-                  message: chrome.i18n.getMessage('mountingMessage'),
-                }, function() {});
-              }, unpacker.app.MOUNTING_NOTIFICATION_DELAY);
+            chrome.fileSystem.getDisplayPath(
+                item.entry, function(entry, fileSystemId) {
+                  // If loading takes significant amount of time, then show a
+                  // notification about scanning in progress.
+                  var deferredNotificationTimer = setTimeout(function() {
+                    chrome.notifications.create(
+                        fileSystemId, {
+                          type: 'basic',
+                          iconUrl: chrome.runtime.getManifest().icons[128],
+                          title: entry.name,
+                          message: chrome.i18n.getMessage('mountingMessage'),
+                        },
+                        function() {});
+                  }, unpacker.app.MOUNTING_NOTIFICATION_DELAY);
 
-              var onError = function(error, fileSystemId) {
-                clearTimeout(deferredNotificationTimer);
-                console.error('Mount error: ' + error.message + '.');
-                // Decrement the counter that indicates the number of ongoing
-                // mount process.
-                unpacker.app.mountProcessCounter--;
-                if (error.message === 'EXISTS') {
-                  if (opt_onError)
-                    opt_onError(fileSystemId);
-                  return;
-                }
-                chrome.notifications.create(fileSystemId, {
-                  type: 'basic',
-                  iconUrl: chrome.runtime.getManifest().icons[128],
-                  title: entry.name,
-                  message: chrome.i18n.getMessage('otherErrorMessage')
-                }, function() {});
-                if (opt_onError)
-                  opt_onError(fileSystemId);
-                // Cleanup volume resources in order to allow future attempts
-                // to mount the volume. The volume can't be cleaned up in
-                // case of 'EXIST' because we should not clean the other
-                // already mounted volume.
-                unpacker.app.cleanupVolume(fileSystemId);
-              };
+                  var onError = function(error, fileSystemId) {
+                    clearTimeout(deferredNotificationTimer);
+                    console.error('Mount error: ' + error.message + '.');
+                    // Decrement the counter that indicates the number of
+                    // ongoing mount process.
+                    unpacker.app.mountProcessCounter--;
+                    if (error.message === 'EXISTS') {
+                      if (opt_onError)
+                        opt_onError(fileSystemId);
+                      return;
+                    }
+                    chrome.notifications.create(
+                        fileSystemId, {
+                          type: 'basic',
+                          iconUrl: chrome.runtime.getManifest().icons[128],
+                          title: entry.name,
+                          message: chrome.i18n.getMessage('otherErrorMessage')
+                        },
+                        function() {});
+                    if (opt_onError)
+                      opt_onError(fileSystemId);
+                    // Cleanup volume resources in order to allow future
+                    // attempts to mount the volume. The volume can't be cleaned
+                    // up in case of 'EXIST' because we should not clean the
+                    // other already mounted volume.
+                    unpacker.app.cleanupVolume(fileSystemId);
+                  };
 
-              var onSuccess = function(fileSystemId) {
-                clearTimeout(deferredNotificationTimer);
-                chrome.notifications.clear(fileSystemId, function() {});
-                // Decrement the counter that indicates the number of ongoing
-                // mount process.
-                unpacker.app.mountProcessCounter--;
-                if (opt_onSuccess)
-                  opt_onSuccess(fileSystemId);
-              };
+                  var onSuccess = function(fileSystemId) {
+                    clearTimeout(deferredNotificationTimer);
+                    chrome.notifications.clear(fileSystemId, function() {});
+                    // Decrement the counter that indicates the number of
+                    // ongoing mount process.
+                    unpacker.app.mountProcessCounter--;
+                    if (opt_onSuccess)
+                      opt_onSuccess(fileSystemId);
+                  };
 
-              var loadPromise = unpacker.app.loadVolume_(
-                  fileSystemId, entry, {}, '' /* passphrase */);
-              loadPromise.then(function() {
-                // Mount the volume and save its information in local storage
-                // in order to be able to recover the metadata in case of
-                // restarts, system crashes, etc.
-                chrome.fileSystemProvider.mount({
-                  fileSystemId: fileSystemId,
-                  displayName: entry.name,
-                  openedFilesLimit: 1
-                },
-                function() {
-                  if (chrome.runtime.lastError) {
-                    onError(chrome.runtime.lastError, fileSystemId);
-                    return;
-                  }
-                  // Save state so in case of restarts we are able to correctly
-                  // get the archive's metadata.
-                  unpacker.app.saveState_([fileSystemId]);
-                  onSuccess(fileSystemId);
-                });
-              }).catch(function(error) {
-                onError(error.stack || error, fileSystemId);
-                return Promise.reject(error);
-              });
+                  var loadPromise = unpacker.app.loadVolume_(
+                      fileSystemId, entry, {}, '' /* passphrase */);
+                  loadPromise
+                      .then(function() {
+                        // Mount the volume and save its information in local
+                        // storage in order to be able to recover the metadata
+                        // in case of restarts, system crashes, etc.
+                        chrome.fileSystemProvider.mount(
+                            {
+                              fileSystemId: fileSystemId,
+                              displayName: entry.name,
+                              openedFilesLimit: 1
+                            },
+                            function() {
+                              if (chrome.runtime.lastError) {
+                                onError(chrome.runtime.lastError, fileSystemId);
+                                return;
+                              }
+                              // Save state so in case of restarts we are able
+                              // to correctly get the archive's metadata.
+                              unpacker.app.saveState_([fileSystemId]);
+                              onSuccess(fileSystemId);
+                            });
+                      })
+                      .catch(function(error) {
+                        onError(error.stack || error, fileSystemId);
+                        return Promise.reject(error);
+                      });
 
-              unpacker.app.volumeLoadedPromises[fileSystemId] = loadPromise;
-            }.bind(null, item.entry));
+                  unpacker.app.volumeLoadedPromises[fileSystemId] = loadPromise;
+                }.bind(null, item.entry));
           });
         })
-        .catch(function(error) { console.error(error.stack || error); });
+        .catch(function(error) {
+          console.error(error.stack || error);
+        });
   },
 
   /**
@@ -825,7 +839,7 @@
       return;
     }
 
-    if (launchData.id === "pack")
+    if (launchData.id === 'pack')
       unpacker.app.onLaunchedWithPack(launchData);
     else
       unpacker.app.onLaunchedWithUnpack(launchData, opt_onSuccess, opt_onError);
diff --git a/ui/file_manager/zip_archiver/js/background.js b/chrome/browser/resources/chromeos/zip_archiver/js/background.js
similarity index 93%
rename from ui/file_manager/zip_archiver/js/background.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/background.js
index 941e54b..1badd359 100644
--- a/ui/file_manager/zip_archiver/js/background.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/background.js
@@ -26,4 +26,4 @@
     unpacker.app.onReadFileRequested);
 
 // Load the PNaCl module.
-unpacker.app.loadNaclModule('module.nmf.txt', 'application/x-pnacl');
+unpacker.app.loadNaclModule('module.nmf', 'application/x-pnacl');
diff --git a/ui/file_manager/zip_archiver/js/build-config.js b/chrome/browser/resources/chromeos/zip_archiver/js/build-config.js
similarity index 100%
rename from ui/file_manager/zip_archiver/js/build-config.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/build-config.js
diff --git a/chrome/browser/resources/chromeos/zip_archiver/js/compressor-foreground.js b/chrome/browser/resources/chromeos/zip_archiver/js/compressor-foreground.js
new file mode 100644
index 0000000..3a7e387
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/compressor-foreground.js
@@ -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.
+
+window.onload = function() {
+  chrome.runtime.getBackgroundPage(function(backgroundPage) {
+
+    // Called from the background page. We need to place this function here
+    // because chrome.fileSystem.chooseEntry only works on forground page.
+    backgroundPage.unpacker.Compressor.prototype.createArchiveFileForeground_ =
+        function(compressorId) {
+      var compressor = backgroundPage.unpacker.app.compressors[compressorId];
+      var suggestedName = compressor.archiveName_;
+      // Create an archive file.
+      chrome.fileSystem.chooseEntry(
+          {type: 'saveFile', suggestedName: suggestedName},
+          function(entry, fileEntries) {
+            if (!entry) {
+              console.error('Failed to create an archive file.');
+              compressor.onError_(compressor.compressorId_);
+              return;
+            }
+
+            compressor.archiveFileEntry_ = entry;
+
+            compressor.sendCreateArchiveRequest_();
+          });
+    };
+
+    // Some compressors are waiting for this foreground page to be loaded.
+    backgroundPage.unpacker.Compressor.CompressorIdQueue.forEach(function(
+        compressorId) {
+      var compressor = backgroundPage.unpacker.app.compressors[compressorId];
+      compressor.createArchiveFileForeground_(compressorId);
+    });
+  });
+};
diff --git a/ui/file_manager/zip_archiver/js/compressor.js b/chrome/browser/resources/chromeos/zip_archiver/js/compressor.js
similarity index 82%
rename from ui/file_manager/zip_archiver/js/compressor.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/compressor.js
index fa68d7f..40c368bd 100644
--- a/ui/file_manager/zip_archiver/js/compressor.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/compressor.js
@@ -126,7 +126,7 @@
   if (this.items_.length !== 1)
     return unpacker.Compressor.DEFAULT_ARCHIVE_NAME;
 
-  var name = this.items_[0].entry.name
+  var name = this.items_[0].entry.name;
   var idx = name.lastIndexOf('.');
   // When the name does not have extension.
   // TODO(takise): This converts file.tar.gz to file.tar.zip.
@@ -179,10 +179,9 @@
  * @private
  */
 unpacker.Compressor.prototype.sendCreateArchiveRequest_ = function() {
-  var request = unpacker.request.createCreateArchiveRequest(
-      this.compressorId_);
+  var request = unpacker.request.createCreateArchiveRequest(this.compressorId_);
   this.naclModule_.postMessage(request);
-}
+};
 
 /**
  * A handler of create archive done response.
@@ -193,7 +192,7 @@
   this.items_.forEach(function(item) {
     this.getEntryMetadata_(item.entry);
   }.bind(this));
-}
+};
 
 /**
  * Gets metadata of a file or directory.
@@ -205,7 +204,7 @@
     this.getSingleMetadata_(entry);
   else
     this.getDirectoryEntryMetadata_(/** @type {!DirectoryEntry} */ (entry));
-}
+};
 
 /**
  * Requests metadata of an entry non-recursively.
@@ -217,17 +216,18 @@
   this.metadataRequestsInProgress_.add(entryId);
   this.entries_[entryId] = entry;
 
-  entry.getMetadata(function(metadata) {
-    this.metadataRequestsInProgress_.delete(entryId);
-    this.pendingAddToArchiveRequests_.push(entryId);
-    this.metadata_[entryId] = metadata;
-    this.sendAddToArchiveRequest_();
-  }.bind(this), function(error) {
-    console.error('Failed to get metadata: ' +
-        error.message + '.');
-    this.onError_(this.compressorId_);
-  }.bind(this));
-}
+  entry.getMetadata(
+      function(metadata) {
+        this.metadataRequestsInProgress_.delete(entryId);
+        this.pendingAddToArchiveRequests_.push(entryId);
+        this.metadata_[entryId] = metadata;
+        this.sendAddToArchiveRequest_();
+      }.bind(this),
+      function(error) {
+        console.error('Failed to get metadata: ' + error.message + '.');
+        this.onError_(this.compressorId_);
+      }.bind(this));
+};
 
 /**
  * Requests metadata of an entry recursively.
@@ -241,25 +241,27 @@
 
   // Recursive function
   var getEntries = function() {
-    dirReader.readEntries(function(results) {
-      // ReadEntries must be called until it returns nothing, because
-      // it does not necessarily return all entries in the directory.
-      if (results.length) {
-        results.forEach(this.getEntryMetadata_.bind(this));
-        getEntries();
-      }
-    }.bind(this), function(error) {
-      console.error('Failed to get directory entries: ' +
-          error.message + '.');
-      this.onError_(this.compressorId_);
-    }.bind(this));
+    dirReader.readEntries(
+        function(results) {
+          // ReadEntries must be called until it returns nothing, because
+          // it does not necessarily return all entries in the directory.
+          if (results.length) {
+            results.forEach(this.getEntryMetadata_.bind(this));
+            getEntries();
+          }
+        }.bind(this),
+        function(error) {
+          console.error(
+              'Failed to get directory entries: ' + error.message + '.');
+          this.onError_(this.compressorId_);
+        }.bind(this));
   }.bind(this);
 
   getEntries();
 
   // Get the metadata of this dir itself.
   this.getSingleMetadata_(dir);
-}
+};
 
 /**
  * Pops an entry from the queue and adds it to the archive.
@@ -294,11 +296,10 @@
   var modificationTime = utc.getTime() - (utc.getTimezoneOffset() * 60000);
 
   var request = unpacker.request.createAddToArchiveRequest(
-      this.compressorId_, entryId, fullPath,
-      this.metadata_[entryId].size, modificationTime,
-      this.entries_[entryId].isDirectory);
+      this.compressorId_, entryId, fullPath, this.metadata_[entryId].size,
+      modificationTime, this.entries_[entryId].isDirectory);
   this.naclModule_.postMessage(request);
-}
+};
 
 /**
  * Sends a close archive request to minizip. minizip writes metadata of
@@ -306,10 +307,10 @@
  * packing process.
  */
 unpacker.Compressor.prototype.sendCloseArchiveRequest = function(hasError) {
-  var request = unpacker.request.createCloseArchiveRequest(
-      this.compressorId_, hasError);
+  var request =
+      unpacker.request.createCloseArchiveRequest(this.compressorId_, hasError);
   this.naclModule_.postMessage(request);
-}
+};
 
 /**
  * Sends a read file chunk done response.
@@ -317,12 +318,12 @@
  * @param {!ArrayBuffer} buffer A buffer containing the data that was read.
  * @private
  */
-unpacker.Compressor.prototype.sendReadFileChunkDone_ =
-    function(length, buffer) {
+unpacker.Compressor.prototype.sendReadFileChunkDone_ = function(
+    length, buffer) {
   var request = unpacker.request.createReadFileChunkDoneResponse(
       this.compressorId_, length, buffer);
   this.naclModule_.postMessage(request);
-}
+};
 
 /**
  * A handler of read file chunk messages.
@@ -346,7 +347,8 @@
       // The buffer must have 'length' bytes because the byte length which can
       // be read from the file is already calculated on NaCL side.
       if (buffer.byteLength !== length) {
-        console.error('Tried to read chunk with length ' + length +
+        console.error(
+            'Tried to read chunk with length ' + length +
             ', but byte with length ' + buffer.byteLength + ' was returned.');
 
         // If the first argument(length) is negative, it means that an error
@@ -361,14 +363,15 @@
     }.bind(this);
 
     reader.onerror = function(event) {
-      console.error('Failed to read file chunk. Name: ' + file.name +
+      console.error(
+          'Failed to read file chunk. Name: ' + file.name +
           ', offset: ' + this.offset_ + ', length: ' + length + '.');
 
       // If the first argument(length) is negative, it means that an error
       // occurred in reading a chunk.
       this.sendReadFileChunkDone_(-1, new ArrayBuffer(0));
       this.onError_(this.compressorId_);
-    }
+    };
 
     reader.readAsArrayBuffer(file);
   }.bind(this);
@@ -384,7 +387,7 @@
 
   // From the second time onward.
   readFileChunk();
-}
+};
 
 /**
  * A handler of write chunk requests.
@@ -397,7 +400,7 @@
   var length = Number(data[unpacker.request.Key.LENGTH]);
   var buffer = data[unpacker.request.Key.CHUNK_BUFFER];
   this.writeChunk_(offset, length, buffer, this.sendWriteChunkDone_.bind(this));
-}
+};
 
 /**
  * Writes buffer into the archive file (window.archiveFileEntry).
@@ -410,33 +413,36 @@
  *     a negative value must be assigned to this argument.
  * @private
  */
-unpacker.Compressor.prototype.writeChunk_ = function(offset, length, buffer,
-    callback) {
+unpacker.Compressor.prototype.writeChunk_ = function(
+    offset, length, buffer, callback) {
   // TODO(takise): Use the same instance of FileWriter over multiple calls of
   // this function instead of creating new ones.
-  this.archiveFileEntry_.createWriter(function(fileWriter) {
-    fileWriter.onwriteend = function(event) {
-      callback(length);
-    };
+  this.archiveFileEntry_.createWriter(
+      function(fileWriter) {
+        fileWriter.onwriteend = function(event) {
+          callback(length);
+        };
 
-    fileWriter.onerror = function(event) {
-      console.error('Failed to write chunk to ' + this.archiveFileEntry_ + '.');
+        fileWriter.onerror = function(event) {
+          console.error(
+              'Failed to write chunk to ' + this.archiveFileEntry_ + '.');
 
-      // If the first argument(length) is negative, it means that an error
-      // occurred in writing a chunk.
-      callback(-1 /* length */);
-      this.onError_(this.compressorId_);
-    };
+          // If the first argument(length) is negative, it means that an error
+          // occurred in writing a chunk.
+          callback(-1 /* length */);
+          this.onError_(this.compressorId_);
+        };
 
-    // Create a new Blob and append it to the archive file.
-    var blob = new Blob([buffer], {});
-    fileWriter.seek(offset);
-    fileWriter.write(blob);
-  }, function(event) {
-    console.error('Failed to create writer for ' + this.archiveFileEntry_ +
-        '.');
-    this.onError_(this.compressorId_);
-  });
+        // Create a new Blob and append it to the archive file.
+        var blob = new Blob([buffer], {});
+        fileWriter.seek(offset);
+        fileWriter.write(blob);
+      },
+      function(event) {
+        console.error(
+            'Failed to create writer for ' + this.archiveFileEntry_ + '.');
+        this.onError_(this.compressorId_);
+      });
 };
 
 /**
@@ -445,10 +451,10 @@
  * @private
  */
 unpacker.Compressor.prototype.sendWriteChunkDone_ = function(length) {
-  var request = unpacker.request.createWriteChunkDoneResponse(
-      this.compressorId_, length);
+  var request =
+      unpacker.request.createWriteChunkDoneResponse(this.compressorId_, length);
   this.naclModule_.postMessage(request);
-}
+};
 
 /**
  * A handler of add to archive done responses.
@@ -463,7 +469,7 @@
 
   // Start processing another entry.
   this.sendAddToArchiveRequest_();
-}
+};
 
 /**
  * A handler of close archive responses.
@@ -472,7 +478,7 @@
  */
 unpacker.Compressor.prototype.onCloseArchiveDone_ = function() {
   this.onSuccess_(this.compressorId_);
-}
+};
 
 /**
  * Processes messages from NaCl module.
@@ -503,9 +509,10 @@
       break;
 
     case unpacker.request.Operation.COMPRESSOR_ERROR:
-      console.error('Compressor error for compressor id ' + this.compressorId_ +
-       ': ' + data[unpacker.request.Key.ERROR]);  // The error contains
-                                                  // the '.' at the end.
+      console.error(
+          'Compressor error for compressor id ' + this.compressorId_ + ': ' +
+          data[unpacker.request.Key.ERROR]);  // The error contains
+                                              // the '.' at the end.
       this.onError_(this.compressorId_);
       break;
 
diff --git a/ui/file_manager/zip_archiver/js/decompressor.js b/chrome/browser/resources/chromeos/zip_archiver/js/decompressor.js
similarity index 75%
rename from ui/file_manager/zip_archiver/js/decompressor.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/decompressor.js
index 1de4aa5..504c2ac 100644
--- a/ui/file_manager/zip_archiver/js/decompressor.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/decompressor.js
@@ -15,8 +15,8 @@
  * @param {!Blob} blob The correspondent file blob for fileSystemId.
  * @param {!unpacker.PassphraseManager} passphraseManager Passphrase manager.
  */
-unpacker.Decompressor = function(naclModule, fileSystemId, blob,
-                                 passphraseManager) {
+unpacker.Decompressor = function(
+    naclModule, fileSystemId, blob, passphraseManager) {
   /**
    * @private {!Object}
    * @const
@@ -68,15 +68,13 @@
  *     postMessage.
  * @private
  */
-unpacker.Decompressor.prototype.addRequest_ = function(requestId, onSuccess,
-                                                       onError, naclRequest) {
-  console.assert(!this.requestsInProgress[requestId],
-                 'There is already a request with the id ' + requestId + '.');
+unpacker.Decompressor.prototype.addRequest_ = function(
+    requestId, onSuccess, onError, naclRequest) {
+  console.assert(
+      !this.requestsInProgress[requestId],
+      'There is already a request with the id ' + requestId + '.');
 
-  this.requestsInProgress[requestId] = {
-    onSuccess: onSuccess,
-    onError: onError
-  };
+  this.requestsInProgress[requestId] = {onSuccess: onSuccess, onError: onError};
 
   this.naclModule_.postMessage(naclRequest);
 };
@@ -91,12 +89,12 @@
  *     and as value information about the entry.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Decompressor.prototype.readMetadata = function(requestId, encoding,
-                                                        onSuccess, onError) {
+unpacker.Decompressor.prototype.readMetadata = function(
+    requestId, encoding, onSuccess, onError) {
   this.addRequest_(
       requestId, onSuccess, onError,
-      unpacker.request.createReadMetadataRequest(this.fileSystemId_, requestId,
-                                                 encoding, this.blob_.size));
+      unpacker.request.createReadMetadataRequest(
+          this.fileSystemId_, requestId, encoding, this.blob_.size));
 };
 
 /**
@@ -107,12 +105,12 @@
  * @param {function()} onSuccess Callback to execute on successful open.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Decompressor.prototype.openFile = function(requestId, index, encoding,
-                                                    onSuccess, onError) {
+unpacker.Decompressor.prototype.openFile = function(
+    requestId, index, encoding, onSuccess, onError) {
   this.addRequest_(
       requestId, onSuccess, onError,
-      unpacker.request.createOpenFileRequest(this.fileSystemId_, requestId,
-                                             index, encoding, this.blob_.size));
+      unpacker.request.createOpenFileRequest(
+          this.fileSystemId_, requestId, index, encoding, this.blob_.size));
 };
 
 /**
@@ -123,11 +121,12 @@
  * @param {function()} onSuccess Callback to execute on successful open.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Decompressor.prototype.closeFile = function(requestId, openRequestId,
-                                                     onSuccess, onError) {
-  this.addRequest_(requestId, onSuccess, onError,
-                   unpacker.request.createCloseFileRequest(
-                       this.fileSystemId_, requestId, openRequestId));
+unpacker.Decompressor.prototype.closeFile = function(
+    requestId, openRequestId, onSuccess, onError) {
+  this.addRequest_(
+      requestId, onSuccess, onError,
+      unpacker.request.createCloseFileRequest(
+          this.fileSystemId_, requestId, openRequestId));
 };
 
 /**
@@ -145,8 +144,8 @@
     requestId, openRequestId, offset, length, onSuccess, onError) {
   this.addRequest_(
       requestId, onSuccess, onError,
-      unpacker.request.createReadFileRequest(this.fileSystemId_, requestId,
-                                             openRequestId, offset, length));
+      unpacker.request.createReadFileRequest(
+          this.fileSystemId_, requestId, openRequestId, offset, length));
 };
 
 /**
@@ -157,13 +156,15 @@
  * @param {number} requestId The request id, which should be unique per every
  *     volume.
  */
-unpacker.Decompressor.prototype.processMessage = function(data, operation,
-                                                          requestId) {
+unpacker.Decompressor.prototype.processMessage = function(
+    data, operation, requestId) {
   // Create a request reference for asynchronous calls as sometimes we delete
   // some requestsInProgress from this.requestsInProgress.
   var requestInProgress = this.requestsInProgress[requestId];
-  console.assert(requestInProgress, 'No request with id <' + requestId +
-                 '> for: ' + this.fileSystemId_ + '.');
+  console.assert(
+      requestInProgress,
+      'No request with id <' + requestId + '> for: ' + this.fileSystemId_ +
+          '.');
 
   switch (operation) {
     case unpacker.request.Operation.READ_METADATA_DONE:
@@ -203,8 +204,9 @@
       var buffer = data[unpacker.request.Key.READ_FILE_DATA];
       console.assert(buffer, 'No buffer for read file operation.');
       var hasMoreData = data[unpacker.request.Key.HAS_MORE_DATA];
-      console.assert(buffer !== undefined,
-                    'No HAS_MORE_DATA boolean value for file operation.');
+      console.assert(
+          buffer !== undefined,
+          'No HAS_MORE_DATA boolean value for file operation.');
 
       requestInProgress.onSuccess(buffer, hasMoreData /* Last call. */);
       if (hasMoreData)
@@ -212,21 +214,23 @@
       break;
 
     case unpacker.request.Operation.FILE_SYSTEM_ERROR:
-      console.error('File system error for <' + this.fileSystemId_ + '>: ' +
-                    data[unpacker.request.Key.ERROR]);  // The error contains
-                                                        // the '.' at the end.
+      console.error(
+          'File system error for <' + this.fileSystemId_ +
+          '>: ' + data[unpacker.request.Key.ERROR]);  // The error contains
+                                                      // the '.' at the end.
       requestInProgress.onError('FAILED');
       break;
 
     case unpacker.request.Operation.CONSOLE_LOG:
     case unpacker.request.Operation.CONSOLE_DEBUG:
-      var src_file = data[unpacker.request.Key.SRC_FILE];
-      var src_line = data[unpacker.request.Key.SRC_LINE];
-      var src_func = data[unpacker.request.Key.SRC_FUNC];
+      var srcFile = data[unpacker.request.Key.SRC_FILE];
+      var srcLine = data[unpacker.request.Key.SRC_LINE];
+      var srcFunc = data[unpacker.request.Key.SRC_FUNC];
       var msg = data[unpacker.request.Key.MESSAGE];
       var log = operation == unpacker.request.Operation.CONSOLE_LOG ?
-                console.log : console.debug;
-      log(src_file + ':' + src_func + ':' + src_line + ': ' + msg);
+          console.log :
+          console.debug;
+      log(srcFile + ':' + srcFunc + ':' + srcLine + ': ' + msg);
       break;
 
     default:
@@ -245,19 +249,20 @@
  */
 unpacker.Decompressor.prototype.readChunk_ = function(data, requestId) {
   // Offset and length are received as strings. See request.js.
-  var offset_str = data[unpacker.request.Key.OFFSET];
-  var length_str = data[unpacker.request.Key.LENGTH];
+  var offsetStr = data[unpacker.request.Key.OFFSET];
+  var lengthStr = data[unpacker.request.Key.LENGTH];
 
   // Explicit check if offset is undefined as it can be 0.
-  console.assert(offset_str !== undefined && !isNaN(offset_str) &&
-                     Number(offset_str) >= 0 &&
-                     Number(offset_str) < this.blob_.size,
-                 'Invalid offset.');
-  console.assert(length_str && !isNaN(length_str) && Number(length_str) > 0,
-                 'Invalid length.');
+  console.assert(
+      offsetStr !== undefined && !isNaN(offsetStr) && Number(offsetStr) >= 0 &&
+          Number(offsetStr) < this.blob_.size,
+      'Invalid offset.');
+  console.assert(
+      lengthStr && !isNaN(lengthStr) && Number(lengthStr) > 0,
+      'Invalid length.');
 
-  var offset = Number(offset_str);
-  var length = Math.min(this.blob_.size - offset, Number(length_str));
+  var offset = Number(offsetStr);
+  var length = Math.min(this.blob_.size - offset, Number(lengthStr));
 
   // Read a chunk from offset to offset + length.
   var blob = this.blob_.slice(offset, offset + length);
diff --git a/ui/file_manager/zip_archiver/js/passphrase-dialog.js b/chrome/browser/resources/chromeos/zip_archiver/js/passphrase-dialog.js
similarity index 97%
rename from ui/file_manager/zip_archiver/js/passphrase-dialog.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/passphrase-dialog.js
index d7ae07a..4cc7936 100644
--- a/ui/file_manager/zip_archiver/js/passphrase-dialog.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/passphrase-dialog.js
@@ -8,7 +8,7 @@
  */
 
 Polymer({
-  is: "passphrase-dialog",
+  is: 'passphrase-dialog',
   i18n: function(name) {
     // For tests, chrome.i18n API is not available.
     return chrome.i18n ? chrome.i18n.getMessage(name) : name;
diff --git a/ui/file_manager/zip_archiver/js/passphrase-manager.js b/chrome/browser/resources/chromeos/zip_archiver/js/passphrase-manager.js
similarity index 79%
rename from ui/file_manager/zip_archiver/js/passphrase-manager.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/passphrase-manager.js
index 1b474c4..655d45b 100644
--- a/ui/file_manager/zip_archiver/js/passphrase-manager.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/passphrase-manager.js
@@ -23,7 +23,7 @@
 /**
  * Requests a passphrase from the user. If a passphrase was previously
  * remembered, then tries it first. Otherwise shows a passphrase dialog.
- * @return {!Promise.<string>}
+ * @return {!Promise<string>}
  */
 unpacker.PassphraseManager.prototype.getPassphrase = function() {
   return new Promise(function(fulfill, reject) {
@@ -54,12 +54,13 @@
             reject('FAILED');
           }.bind(this));
 
-          passphraseWindow.contentWindow.onPassphraseSuccess =
-              function(passphrase, remember) {
-                passphraseSucceeded = true;
-                this.rememberedPassphrase = remember ? passphrase : null;
-                fulfill(passphrase);
-              }.bind(this);
+          passphraseWindow.contentWindow.onPassphraseSuccess = function(
+                                                                   passphrase,
+                                                                   remember) {
+            passphraseSucceeded = true;
+            this.rememberedPassphrase = remember ? passphrase : null;
+            fulfill(passphrase);
+          }.bind(this);
         }.bind(this));
   }.bind(this));
-}
+};
diff --git a/ui/file_manager/zip_archiver/js/request.js b/chrome/browser/resources/chromeos/zip_archiver/js/request.js
similarity index 84%
rename from ui/file_manager/zip_archiver/js/request.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/request.js
index fe1e01a..b8439b8 100644
--- a/ui/file_manager/zip_archiver/js/request.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/request.js
@@ -27,35 +27,35 @@
                                    // supported by pp::Var on C++.
     INDEX: 'index',        // Should be a string. Same reason as ARCHIVE_SIZE.
     ENCODING: 'encoding',  // Should be a string.
-    OPEN_REQUEST_ID: 'open_request_id',     // Should be a string, just like
-                                            // REQUEST_ID.
-    READ_FILE_DATA: 'read_file_data',       // Should be an ArrayBuffer.
-    HAS_MORE_DATA: 'has_more_data',         // Should be a boolean.
-    PASSPHRASE: 'passphrase',               // Should be a string.
+    OPEN_REQUEST_ID: 'open_request_id',  // Should be a string, just like
+                                         // REQUEST_ID.
+    READ_FILE_DATA: 'read_file_data',    // Should be an ArrayBuffer.
+    HAS_MORE_DATA: 'has_more_data',      // Should be a boolean.
+    PASSPHRASE: 'passphrase',            // Should be a string.
     SRC_FILE: 'src_file',                // Should be a string.
     SRC_LINE: 'src_line',                // Should be a int.
     SRC_FUNC: 'src_func',                // Should be a string.
     MESSAGE: 'message',                  // Should be a string.
 
     // Mandatory keys for all packing operations.
-    COMPRESSOR_ID: 'compressor_id',         // Should be an int.
+    COMPRESSOR_ID: 'compressor_id',  // Should be an int.
 
     // Optional keys unique to packing operations.
-    ENTRY_ID: 'entry_id',                   // Should be an int.
-    PATHNAME: 'pathname',                   // should be a string.
-    FILE_SIZE: 'file_size',                 // should be a string. Same reason
-                                            // as ARCHIVE_SIZE.
-    IS_DIRECTORY: 'is_directory',           // should be a boolean.
-    MODIFICATION_TIME: 'modification_time', // should be a string.
-                                            // (mm/dd/yy h:m:s)
-    HAS_ERROR: 'has_error',                 // Should be a boolean Sent from JS
-                                            // to NaCL.
+    ENTRY_ID: 'entry_id',                    // Should be an int.
+    PATHNAME: 'pathname',                    // should be a string.
+    FILE_SIZE: 'file_size',                  // should be a string. Same reason
+                                             // as ARCHIVE_SIZE.
+    IS_DIRECTORY: 'is_directory',            // should be a boolean.
+    MODIFICATION_TIME: 'modification_time',  // should be a string.
+                                             // (mm/dd/yy h:m:s)
+    HAS_ERROR: 'has_error',                  // Should be a boolean Sent from JS
+                                             // to NaCL.
 
     // Optional keys used for both packing and unpacking operations.
     ERROR: 'error',                // Should be a string.
     CHUNK_BUFFER: 'chunk_buffer',  // Should be an ArrayBuffer.
-    OFFSET: 'offset',      // Should be a string. Same reason as ARCHIVE_SIZE.
-    LENGTH: 'length'       // Should be a string. Same reason as ARCHIVE_SIZE.
+    OFFSET: 'offset',  // Should be a string. Same reason as ARCHIVE_SIZE.
+    LENGTH: 'length'   // Should be a string. Same reason as ARCHIVE_SIZE.
   },
 
   /**
@@ -98,19 +98,19 @@
   },
 
   /**
-  * Operations greater than or equal to this value are for packing.
-  * @const {number}
-  */
+   * Operations greater than or equal to this value are for packing.
+   * @const {number}
+   */
   MINIMUM_PACK_REQUEST_VALUE: 17,
 
   /**
-  * Return true if the given operation is related to packing.
-  * @param {!unpacker.request.Operation} operation
-  * @return {boolean}
-  */
+   * Return true if the given operation is related to packing.
+   * @param {!unpacker.request.Operation} operation
+   * @return {boolean}
+   */
   isPackRequest: function(operation) {
     return unpacker.request.MINIMUM_PACK_REQUEST_VALUE <= operation ||
-           operation == unpacker.request.Operation.COMPRESSOR_ERROR;
+        operation == unpacker.request.Operation.COMPRESSOR_ERROR;
   },
 
   /**
@@ -138,8 +138,8 @@
    * @param {number} archiveSize The size of the archive for fileSystemId.
    * @return {!Object} A read metadata request.
    */
-  createReadMetadataRequest: function(fileSystemId, requestId, encoding,
-                                      archiveSize) {
+  createReadMetadataRequest: function(
+      fileSystemId, requestId, encoding, archiveSize) {
     var readMetadataRequest = unpacker.request.createBasic_(
         unpacker.request.Operation.READ_METADATA, fileSystemId, requestId);
     readMetadataRequest[unpacker.request.Key.ENCODING] = encoding;
@@ -159,8 +159,8 @@
    *     parallel for different offsets.
    * @return {!Object} A read chunk done response.
    */
-  createReadChunkDoneResponse: function(fileSystemId, requestId, buffer,
-                                        readOffset) {
+  createReadChunkDoneResponse: function(
+      fileSystemId, requestId, buffer, readOffset) {
     var response = unpacker.request.createBasic_(
         unpacker.request.Operation.READ_CHUNK_DONE, fileSystemId, requestId);
     response[unpacker.request.Key.CHUNK_BUFFER] = buffer;
@@ -189,8 +189,8 @@
    * @param {string} passphrase The passphrase.
    * @return {!Object} A read passphrase done response.
    */
-  createReadPassphraseDoneResponse: function(fileSystemId, requestId,
-                                             passphrase) {
+  createReadPassphraseDoneResponse: function(
+      fileSystemId, requestId, passphrase) {
     var response = unpacker.request.createBasic_(
         unpacker.request.Operation.READ_PASSPHRASE_DONE, fileSystemId,
         requestId);
@@ -231,8 +231,8 @@
    * @param {number} archiveSize The size of the volume's archive.
    * @return {!Object} An open file request.
    */
-  createOpenFileRequest: function(fileSystemId, requestId, index, encoding,
-                                  archiveSize) {
+  createOpenFileRequest: function(
+      fileSystemId, requestId, index, encoding, archiveSize) {
     var openFileRequest = unpacker.request.createBasic_(
         unpacker.request.Operation.OPEN_FILE, fileSystemId, requestId);
     openFileRequest[unpacker.request.Key.INDEX] = index.toString();
@@ -265,8 +265,8 @@
    * @param {number} length The number of bytes required.
    * @return {!Object} A read file request.
    */
-  createReadFileRequest: function(fileSystemId, requestId, openRequestId,
-                                  offset, length) {
+  createReadFileRequest: function(
+      fileSystemId, requestId, openRequestId, offset, length) {
     var readFileRequest = unpacker.request.createBasic_(
         unpacker.request.Operation.READ_FILE, fileSystemId, requestId);
     readFileRequest[unpacker.request.Key.OPEN_REQUEST_ID] =
@@ -299,8 +299,9 @@
    * @param {boolean} isDirectory Whether the entry is a directory or not.
    * @return {!Object} An add to archive request.
    */
-  createAddToArchiveRequest: function(compressorId, entryId, pathname,
-                                      fileSize, modificationTime, isDirectory) {
+  createAddToArchiveRequest: function(
+      compressorId, entryId, pathname, fileSize, modificationTime,
+      isDirectory) {
     var request = {};
     request[unpacker.request.Key.OPERATION] =
         unpacker.request.Operation.ADD_TO_ARCHIVE;
diff --git a/ui/file_manager/zip_archiver/js/types.js b/chrome/browser/resources/chromeos/zip_archiver/js/types.js
similarity index 100%
rename from ui/file_manager/zip_archiver/js/types.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/types.js
diff --git a/ui/file_manager/zip_archiver/js/unpacker.js b/chrome/browser/resources/chromeos/zip_archiver/js/unpacker.js
similarity index 100%
rename from ui/file_manager/zip_archiver/js/unpacker.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/unpacker.js
diff --git a/ui/file_manager/zip_archiver/js/volume.js b/chrome/browser/resources/chromeos/zip_archiver/js/volume.js
similarity index 89%
rename from ui/file_manager/zip_archiver/js/volume.js
rename to chrome/browser/resources/chromeos/zip_archiver/js/volume.js
index 9fc8f65..0ba76e7 100644
--- a/ui/file_manager/zip_archiver/js/volume.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/js/volume.js
@@ -12,8 +12,8 @@
  */
 function DateFromTimeT(timestamp) {
   var local = new Date(1000 * timestamp);
-  console.info(local.getHours())
-  return new Date( local.getTime() + (local.getTimezoneOffset() * 60000));
+  console.info(local.getHours());
+  return new Date(local.getTime() + (local.getTimezoneOffset() * 60000));
 }
 
 /**
@@ -28,7 +28,8 @@
   entryMetadata.modificationTime =
       DateFromTimeT(entryMetadata.modificationTime);
   if (entryMetadata.isDirectory) {
-    console.assert(entryMetadata.entries,
+    console.assert(
+        entryMetadata.entries,
         'The field "entries" is mandatory for dictionaries.');
     for (var entry in entryMetadata.entries) {
       correctMetadata(entryMetadata.entries[entry]);
@@ -157,7 +158,7 @@
  */
 unpacker.Volume.prototype.inUse = function() {
   return this.decompressor.hasRequestsInProgress() ||
-         Object.keys(this.openedFiles).length > 0;
+      Object.keys(this.openedFiles).length > 0;
 };
 
 /**
@@ -169,8 +170,8 @@
   var requestId = unpacker.Volume.DEFAULT_READ_METADATA_REQUEST_ID;
   this.decompressor.readMetadata(requestId, this.encoding, function(metadata) {
     // Make a deep copy of metadata.
-    this.metadata = /** @type {!Object<string, !EntryMetadata>} */ (JSON.parse(
-            JSON.stringify(metadata)));
+    this.metadata = /** @type {!Object<string, !EntryMetadata>} */ (
+        JSON.parse(JSON.stringify(metadata)));
     correctMetadata(this.metadata);
 
     onSuccess();
@@ -185,8 +186,8 @@
  * @param {function(!EntryMetadata)} onSuccess Callback to execute on success.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Volume.prototype.onGetMetadataRequested = function(options, onSuccess,
-                                                            onError) {
+unpacker.Volume.prototype.onGetMetadataRequested = function(
+    options, onSuccess, onError) {
   console.assert(this.isReady(), 'Metadata must be loaded.');
   var entryMetadata = this.getEntryMetadata_(options.entryPath);
   if (!entryMetadata)
@@ -232,8 +233,8 @@
  * @param {function()} onSuccess Callback to execute on success.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Volume.prototype.onOpenFileRequested = function(options, onSuccess,
-                                                         onError) {
+unpacker.Volume.prototype.onOpenFileRequested = function(
+    options, onSuccess, onError) {
   console.assert(this.isReady(), 'Metadata must be loaded.');
   if (options.mode != 'READ') {
     onError('INVALID_OPERATION');
@@ -249,9 +250,11 @@
   this.openedFiles[options.requestId] = options;
 
   this.decompressor.openFile(
-      options.requestId, metadata.index, this.encoding, function() {
+      options.requestId, metadata.index, this.encoding,
+      function() {
         onSuccess();
-      }.bind(this), function(error) {
+      }.bind(this),
+      function(error) {
         delete this.openedFiles[options.requestId];
         onError('FAILED');
       }.bind(this));
@@ -264,8 +267,8 @@
  * @param {function()} onSuccess Callback to execute on success.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Volume.prototype.onCloseFileRequested = function(options, onSuccess,
-                                                          onError) {
+unpacker.Volume.prototype.onCloseFileRequested = function(
+    options, onSuccess, onError) {
   console.assert(this.isReady(), 'Metadata must be loaded.');
   var openRequestId = options.openRequestId;
   var openOptions = this.openedFiles[openRequestId];
@@ -288,8 +291,8 @@
  *     success.
  * @param {function(!ProviderError)} onError Callback to execute on error.
  */
-unpacker.Volume.prototype.onReadFileRequested = function(options, onSuccess,
-                                                         onError) {
+unpacker.Volume.prototype.onReadFileRequested = function(
+    options, onSuccess, onError) {
   console.assert(this.isReady(), 'Metadata must be loaded.');
   var openOptions = this.openedFiles[options.openRequestId];
   if (!openOptions) {
@@ -310,8 +313,9 @@
   }
   length = Math.min(length, fileSize - offset);
 
-  this.decompressor.readFile(options.requestId, options.openRequestId,
-                             offset, length, onSuccess, onError);
+  this.decompressor.readFile(
+      options.requestId, options.openRequestId, offset, length, onSuccess,
+      onError);
 };
 
 /**
diff --git a/ui/file_manager/zip_archiver/manifest.json b/chrome/browser/resources/chromeos/zip_archiver/manifest.json
similarity index 92%
rename from ui/file_manager/zip_archiver/manifest.json
rename to chrome/browser/resources/chromeos/zip_archiver/manifest.json
index 741c599..49ef7c0 100644
--- a/ui/file_manager/zip_archiver/manifest.json
+++ b/chrome/browser/resources/chromeos/zip_archiver/manifest.json
@@ -1,5 +1,5 @@
 {
-  // chrome-extension://oedeeodfidgoollimchfdnbmhcpnklnd
+  // chrome-extension://dmboannefpncccogfdikhmhpmdnddgoe
   "key": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGxJCOLUzHIYc812NFoBC1eV8PhOTuF6he3gSuqzxckUyrDLdl5++DAd1AkQkv6i8SSMWFvDKLg2b+zfCOwk6P7uu3tqNavXXy61Okaq5HKF3xhciNDl4zF6ZlegvE9AhJOTo2eCHVIMS0+YuK5hyno/+xMwN4byvsrOYXQnhcJeOHxkFb9TfVUb3SOBgl4pBZ7+EIMNntEvzY7mxjBzOgnCjBePvwnoMRyAqljCJarz2WSbUOLP3yoCuH9vPKj+0D6hF1woXmd6qBr0ln/7tHdbr1cYmkosfFuJO2y6d00FAJY/G5L6o8JAEBbWG5D0qELt+aBjkG0uos5gcR4ZPAgMBAAECggEBAK3aIjFJU25J6MjQiRvvY5a4O56bnUIb8SDZgAP6pbwZ7R2R9hiaN6AqVMOiptvgHDZAISYU/OerD4b3s0OCCkvYtlcxwh6iSZQ9BvIighFWrpZRqPHVjDktfQuNIS/dZiiy+9Yr0oFmD4jS45idCPgy+K0h6CEUX9GlPTEq24ElECDwQHVyB9LHdenleCdvldIEDxf6/D+zkc/PmCPlZPfwdppK6wgH2GvgqbxV+OoSnNp0XhNinjCN37P5yAo4xEi0UGOxOwkNGkJn0V5bYjH6/JHzmdVH74D40N4/Fcy0bC79oFGeiP0ZzW8AAArfIxbxStodWlBOCsTVtvi4RMECgYEA2pyZRThGx4OH8uXCC94LkdpVjKvLvbUlIVd2zk3UEFpWujgmAI+erkAaE1JSlcJpFNSlfonTX1vQuMgTOfnK7soy4677P1CMQH++GxjMWRIAQsMyx7vLtKOISr5/vQQKAyuFmxzt9xbMOmPzqWxwkuuiF74GtPgE5VXslhvsoyECgYEAz2U7L6YS4u2aMRK4DMDxcf/hZ3BxwHmUl5euknRNcaFJSdv6392y8w3t9Lz7sp8CK56GADXL1bmLrDgg2tlL82f60rtPd6IOoJk10uMmCnyjbZh7aJzuw1CTSs+dwi6qpGUB4YbJn8R2AN79SHxUb4dwVOh4lHeNa415Wka+a28CgYA3Vf5iDB22cO/fpxLYSCtrjvWqtu3KpmiwqOAU1pSAUy2y03WjHLeQ6f7vtx3adKx+rlj5z89mSuppa5OaUEVy7lG1WlyUqUHnLa6kU0GepjTUsW5QKpQktGRSbygMY1JZfRHDsq31ppqpiRVrZFyWg/iyw9IUytcKahaJ5KWgoQKBgFbgY/ugyNaQi3+1BK4rALktZAGNo8jp5SnfWzx0RaCs3GN5J80xNG4GTsCvjYwUebdF74IVBu7fi7e3x2OFlQBAdVxjJHXLx+7UXyyZBG1uKpOVRVTcMFRW42x6Le6S196HhVMwwDMR/BB/WIBNvJz/kjmvLBudPPtpxwTfD5M3AoGBALrrXX4QwqBiq4q09SPKoeOwlV35QETUhQaAKKag9aSrNMONcf77TXUBZ0d9Z+tabHLTGGa6E7q2BL82NdZSZvVeVWA+KaE4ezW2t5KyZqg14Cc0uY9Xys9VkFcVgMqsvtkUzDvAVJcmNAgcrMIEiapUR6LPrneLLXH1ikOt+hM8",
   // TODO(takise): translation
   "name": "ZIP archiver",
@@ -12,6 +12,7 @@
   "display_in_launcher": false,
   "permissions": [
     "alwaysOnTopWindows",
+    "chrome://resources/",
     "fileSystemProvider",
     {"fileSystem": ["retainEntries", "write", "directory"]},
     "notifications",
@@ -53,6 +54,7 @@
         "js/types.js",
         "js/volume.js"
       ]
-    }
+    },
+    "content_security_policy": "default-src 'none'; script-src chrome://resources; style-src 'unsafe-inline' chrome://resources;"
   }
 }
diff --git a/ui/file_manager/zip_archiver/module.nmf.txt b/chrome/browser/resources/chromeos/zip_archiver/module.nmf
similarity index 64%
rename from ui/file_manager/zip_archiver/module.nmf.txt
rename to chrome/browser/resources/chromeos/zip_archiver/module.nmf
index 04c5b63..a770d700 100644
--- a/ui/file_manager/zip_archiver/module.nmf.txt
+++ b/chrome/browser/resources/chromeos/zip_archiver/module.nmf
@@ -2,7 +2,7 @@
   "program": {
     "portable": {
       "pnacl-translate": {
-        "url": "zip_archiver_pnacl.pexe.js"
+        "url": "zip_archiver_pnacl.pexe"
       }
     }
   }
diff --git a/ui/file_manager/zip_archiver/unpacker-test/.gitignore b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/.gitignore
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/.gitignore
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/.gitignore
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/.gitignore b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/.gitignore
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/.gitignore
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/.gitignore
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/Makefile b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/Makefile
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/Makefile
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/Makefile
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_lib_archive.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_lib_archive.cc
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/fake_lib_archive.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_lib_archive.cc
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_lib_archive.h b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_lib_archive.h
similarity index 89%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/fake_lib_archive.h
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_lib_archive.h
index efe2ea3..6818add 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_lib_archive.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_lib_archive.h
@@ -5,8 +5,8 @@
 // This file contains the common variables shared between the fake
 // implementation of the libarchive API and the other test files.
 
-#ifndef FAKE_LIB_ARCHIVE_H_
-#define FAKE_LIB_ARCHIVE_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_LIB_ARCHIVE_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_LIB_ARCHIVE_H_
 
 #include <limits>
 
@@ -71,4 +71,4 @@
 
 }  // namespace fake_lib_archive_config
 
-#endif  // FAKE_LIB_ARCHIVE_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_LIB_ARCHIVE_H_
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_volume_reader.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_volume_reader.cc
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/fake_volume_reader.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_volume_reader.cc
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_volume_reader.h b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_volume_reader.h
similarity index 74%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/fake_volume_reader.h
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_volume_reader.h
index 1d847d4..24f242f 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/fake_volume_reader.h
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/fake_volume_reader.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef FAKE_VOLUME_READER_H_
-#define FAKE_VOLUME_READER_H_
+#ifndef CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_VOLUME_READER_H_
+#define CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_VOLUME_READER_H_
 
 #include "volume_reader.h"
 
@@ -23,4 +23,4 @@
   const char* Passphrase();
 };
 
-#endif  // FAKE_VOLUME_READER_H_
+#endif  // CHROME_BROWSER_RESOURCES_CHROMEOS_ZIP_ARCHIVER_UNPACKER_TEST_CPP_FAKE_VOLUME_READER_H_
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/index.html b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/index.html
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/index.html
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/index.html
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/index.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/index.js
similarity index 89%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/index.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/index.js
index 543bb14..db03f5d 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/index.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/index.js
@@ -11,9 +11,11 @@
  * @return {string} The corresponding GET parameter value.
  */
 function getUrlParameter(name) {
-  var getUrlRegex = new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)');
+  var getUrlRegex = new RegExp(
+      '[?|&]' + name + '=' +
+      '([^&;]+?)(&|#|;|$)');
   var param =
-      (getUrlRegex.exec(location.search) || [,""])[1].replace(/\+/g, '%20');
+      (getUrlRegex.exec(location.search) || [, ''])[1].replace(/\+/g, '%20');
   return decodeURIComponent(param) || null;
 }
 
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/main.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/main.cc
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/main.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/main.cc
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/request_test.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/request_test.cc
similarity index 97%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/request_test.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/request_test.cc
index ac5e60a..d29e8b8 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/request_test.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/request_test.cc
@@ -130,9 +130,8 @@
 
   EXPECT_TRUE(
       read_file_done.Get(request::key::kReadFileData).is_array_buffer());
-  EXPECT_EQ(
-      array_buffer,
-      pp::VarArrayBuffer(read_file_done.Get(request::key::kReadFileData)));
+  EXPECT_EQ(array_buffer, pp::VarArrayBuffer(
+                              read_file_done.Get(request::key::kReadFileData)));
 
   EXPECT_TRUE(read_file_done.Get(request::key::kHasMoreData).is_bool());
   EXPECT_EQ(has_more_data,
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc
similarity index 98%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc
index cd21ac8..55a93812 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_read_test.cc
@@ -38,8 +38,8 @@
     bool is_directory = false;
     time_t modification_time = 0;
     ASSERT_EQ(VolumeArchive::RESULT_SUCCESS,
-              volume_archive->GetNextHeader(
-                  &path_name, &size, &is_directory, &modification_time));
+              volume_archive->GetNextHeader(&path_name, &size, &is_directory,
+                                            &modification_time));
   }
 
   virtual void TearDown() {
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc
similarity index 95%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc
index ae4e5a0d..493f1f9 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_archive_libarchive_test.cc
@@ -137,8 +137,8 @@
       S_IFREG;  // Regular file.
 
   EXPECT_EQ(VolumeArchive::RESULT_SUCCESS,
-            volume_archive->GetNextHeader(
-                &path_name, &size, &is_directory, &modification_time));
+            volume_archive->GetNextHeader(&path_name, &size, &is_directory,
+                                          &modification_time));
   EXPECT_EQ(expected_path_name, path_name);
   EXPECT_EQ(fake_lib_archive_config::kSize, size);
   EXPECT_EQ(fake_lib_archive_config::kModificationTime, modification_time);
@@ -149,8 +149,8 @@
       S_IFDIR;  // Directory.
 
   EXPECT_EQ(VolumeArchive::RESULT_SUCCESS,
-            volume_archive->GetNextHeader(
-                &path_name, &size, &is_directory, &modification_time));
+            volume_archive->GetNextHeader(&path_name, &size, &is_directory,
+                                          &modification_time));
   EXPECT_EQ(expected_path_name, path_name);
   EXPECT_EQ(fake_lib_archive_config::kSize, size);
   EXPECT_EQ(fake_lib_archive_config::kModificationTime, modification_time);
@@ -191,8 +191,8 @@
   time_t modification_time = 0;
 
   EXPECT_EQ(VolumeArchive::RESULT_FAIL,
-            volume_archive->GetNextHeader(
-                &pathname, &size, &is_directory, &modification_time));
+            volume_archive->GetNextHeader(&pathname, &size, &is_directory,
+                                          &modification_time));
 
   std::string next_header_error =
       std::string(volume_archive_constants::kArchiveNextHeaderErrorPrefix) +
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc
similarity index 97%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc
index 8e33cc8..9d217bd 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_reader_javascript_stream_test.cc
@@ -9,8 +9,8 @@
 
 #include "native_client_sdk/src/libraries/ppapi_simple/ps_main.h"
 #include "ppapi/cpp/instance_handle.h"
-#include "ppapi/utility/threading/simple_thread.h"
 #include "ppapi/utility/completion_callback_factory.h"
+#include "ppapi/utility/threading/simple_thread.h"
 #include "testing/gtest/gtest.h"
 
 // Fake JavaScriptRequestor that responds to
@@ -36,8 +36,7 @@
                         int64_t offset,
                         int64_t bytes_to_read) {
     worker_.message_loop().PostWork(callback_factory_.NewCallback(
-        &FakeJavaScriptRequestor::RequestFileChunkCallback,
-        offset,
+        &FakeJavaScriptRequestor::RequestFileChunkCallback, offset,
         bytes_to_read));
   }
 
@@ -120,8 +119,8 @@
     fake_javascript_requestor = new FakeJavaScriptRequestor(instance_handle);
     ASSERT_TRUE(fake_javascript_requestor->Init());
 
-    volume_reader = new VolumeReaderJavaScriptStream(
-        kArchiveSize, fake_javascript_requestor);
+    volume_reader = new VolumeReaderJavaScriptStream(kArchiveSize,
+                                                     fake_javascript_requestor);
     fake_javascript_requestor->SetVolumeReader(volume_reader);
     ASSERT_EQ(0, volume_reader->offset());
   }
diff --git a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_test.cc b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_test.cc
similarity index 95%
rename from ui/file_manager/zip_archiver/unpacker-test/cpp/volume_test.cc
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_test.cc
index a6df014f..9ad35c85 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/cpp/volume_test.cc
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/cpp/volume_test.cc
@@ -5,9 +5,8 @@
 #include "volume.h"
 
 #include "native_client_sdk/src/libraries/ppapi_simple/ps_main.h"
-#include "testing/gtest/gtest.h"
-
 #include "request.h"
+#include "testing/gtest/gtest.h"
 
 namespace {
 
@@ -58,8 +57,8 @@
     message_sender = new FakeJavaScriptMessageSender();
     // TODO(cmihail): Use the constructor with custom factories for
     // VolumeArchive and VolumeReader.
-    volume = new Volume(
-        pp::InstanceHandle(PSGetInstanceId()), kFileSystemId, message_sender);
+    volume = new Volume(pp::InstanceHandle(PSGetInstanceId()), kFileSystemId,
+                        message_sender);
   }
 
   virtual void TearDown() {
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/decompressor_test.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/decompressor_test.js
similarity index 65%
rename from ui/file_manager/zip_archiver/unpacker-test/js/decompressor_test.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/decompressor_test.js
index a82e6a5..eb97335 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/decompressor_test.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/decompressor_test.js
@@ -53,8 +53,8 @@
   /**
    * @const {!Blob}
    */
-  var BLOB = new Blob([new Uint8Array(100)],
-                      {type: 'application/octet-stream'});
+  var BLOB =
+      new Blob([new Uint8Array(100)], {type: 'application/octet-stream'});
 
   var naclModule;
   var decompressor;
@@ -78,9 +78,9 @@
   });
 
   it('should not have any requests in progress if no method was called',
-      function() {
-    expect(Object.keys(decompressor.requestsInProgress).length).to.equal(0);
-  });
+     function() {
+       expect(Object.keys(decompressor.requestsInProgress).length).to.equal(0);
+     });
 
   // Test readMetadata.
   describe('that reads metadata', function() {
@@ -107,31 +107,31 @@
        });
 
     // Test READ_METADATA_DONE.
-    describe('and receives a processMessage with READ_METADATA_DONE',
-             function() {
-      var data = {};
-      beforeEach(function() {
-        data[unpacker.request.Key.METADATA] = 'metadata';  // Not important.
-        decompressor.processMessage(
-            data, unpacker.request.Operation.READ_METADATA_DONE,
-            METADATA_REQUEST_ID);
-      });
+    describe(
+        'and receives a processMessage with READ_METADATA_DONE', function() {
+          var data = {};
+          beforeEach(function() {
+            data[unpacker.request.Key.METADATA] = 'metadata';  // Not important.
+            decompressor.processMessage(
+                data, unpacker.request.Operation.READ_METADATA_DONE,
+                METADATA_REQUEST_ID);
+          });
 
-      it('should call onSuccess with the metadata', function() {
-        expect(onSuccessSpy.calledWith(data[unpacker.request.Key.METADATA]))
-            .to.be.true;
-        expect(onSuccessSpy.calledOnce).to.be.true;
-      });
+          it('should call onSuccess with the metadata', function() {
+            expect(onSuccessSpy.calledWith(data[unpacker.request.Key.METADATA]))
+                .to.be.true;
+            expect(onSuccessSpy.calledOnce).to.be.true;
+          });
 
-      it('should not call onError', function() {
-        expect(onErrorSpy.called).to.be.false;
-      });
+          it('should not call onError', function() {
+            expect(onErrorSpy.called).to.be.false;
+          });
 
-      it('should remove the request in progress', function() {
-        expect(decompressor.requestsInProgress[METADATA_REQUEST_ID])
-            .to.be.undefined;
-      });
-    });
+          it('should remove the request in progress', function() {
+            expect(decompressor.requestsInProgress[METADATA_REQUEST_ID])
+                .to.be.undefined;
+          });
+        });
 
     // Test READ_CHUNK.
     describe('and receives a processMessage with READ_CHUNK', function() {
@@ -151,9 +151,9 @@
                expect(response).to.deep.equal(expectedResponse);
                done();
              };
-             decompressor.processMessage(data,
-                                         unpacker.request.Operation.READ_CHUNK,
-                                         METADATA_REQUEST_ID);
+             decompressor.processMessage(
+                 data, unpacker.request.Operation.READ_CHUNK,
+                 METADATA_REQUEST_ID);
            });
       });
 
@@ -171,45 +171,45 @@
                expect(response).to.deep.equal(expectedResponse);
                done();
              };
-             decompressor.processMessage(data,
-                                         unpacker.request.Operation.READ_CHUNK,
-                                         METADATA_REQUEST_ID);
+             decompressor.processMessage(
+                 data, unpacker.request.Operation.READ_CHUNK,
+                 METADATA_REQUEST_ID);
            });
       });
     });
 
     // Test FILE_SYSTEM_ERROR.
-    describe('and receives a processMessage with FILE_SYSTEM_ERROR',
-             function() {
-      beforeEach(function() {
-        var data = {};
-        data[unpacker.request.Key.ERROR] =
-            'Expected error at reading metadata.';
-        decompressor.processMessage(
-            data, unpacker.request.Operation.FILE_SYSTEM_ERROR,
-            METADATA_REQUEST_ID);
-      });
+    describe(
+        'and receives a processMessage with FILE_SYSTEM_ERROR', function() {
+          beforeEach(function() {
+            var data = {};
+            data[unpacker.request.Key.ERROR] =
+                'Expected error at reading metadata.';
+            decompressor.processMessage(
+                data, unpacker.request.Operation.FILE_SYSTEM_ERROR,
+                METADATA_REQUEST_ID);
+          });
 
-      it('should not call onSuccess', function() {
-        expect(onSuccessSpy.called).to.be.false;
-      });
+          it('should not call onSuccess', function() {
+            expect(onSuccessSpy.called).to.be.false;
+          });
 
-      it('should call onError with FAILED', function() {
-        expect(onErrorSpy.calledWith('FAILED')).to.be.true;
-      });
+          it('should call onError with FAILED', function() {
+            expect(onErrorSpy.calledWith('FAILED')).to.be.true;
+          });
 
-      it('should remove the request in progress', function() {
-        expect(decompressor.requestsInProgress[METADATA_REQUEST_ID])
-            .to.be.undefined;
-      });
-    });
+          it('should remove the request in progress', function() {
+            expect(decompressor.requestsInProgress[METADATA_REQUEST_ID])
+                .to.be.undefined;
+          });
+        });
   });  // Test readMetadata.
 
   // Test openFile.
   describe('that opens a file', function() {
     beforeEach(function() {
-      decompressor.openFile(OPEN_REQUEST_ID, FILE_PATH, ENCODING, onSuccessSpy,
-                            onErrorSpy);
+      decompressor.openFile(
+          OPEN_REQUEST_ID, FILE_PATH, ENCODING, onSuccessSpy, onErrorSpy);
     });
 
     it('should add a new open request in progress', function() {
@@ -230,9 +230,9 @@
     // Test OPEN_FILE_DONE.
     describe('and receives a processMessage with OPEN_FILE_DONE', function() {
       beforeEach(function() {
-        decompressor.processMessage({} /* Not important. */,
-                                    unpacker.request.Operation.OPEN_FILE_DONE,
-                                    OPEN_REQUEST_ID);
+        decompressor.processMessage(
+            {} /* Not important. */, unpacker.request.Operation.OPEN_FILE_DONE,
+            OPEN_REQUEST_ID);
       });
 
       it('should call onSuccess once', function() {
@@ -256,8 +256,8 @@
         onSuccessSpy = sinon.spy();
         onErrorSpy = sinon.spy();
 
-        decompressor.closeFile(CLOSE_REQUEST_ID, OPEN_REQUEST_ID, onSuccessSpy,
-                               onErrorSpy);
+        decompressor.closeFile(
+            CLOSE_REQUEST_ID, OPEN_REQUEST_ID, onSuccessSpy, onErrorSpy);
       });
 
       it('should add a new close request in progress', function() {
@@ -278,36 +278,36 @@
                .to.be.true;
          });
 
-      describe('and receives a processMessage with CLOSE_FILE_DONE',
+      describe(
+          'and receives a processMessage with CLOSE_FILE_DONE', function() {
+            var data = {};
+            beforeEach(function() {
+              data[unpacker.request.Key.OPEN_REQUEST_ID] = OPEN_REQUEST_ID;
+              decompressor.processMessage(
+                  data, unpacker.request.Operation.CLOSE_FILE_DONE,
+                  CLOSE_REQUEST_ID);
+            });
+
+            it('should call onSuccess once', function() {
+              expect(onSuccessSpy.calledOnce).to.be.true;
+            });
+
+            it('should not call onError', function() {
+              expect(onErrorSpy.called).to.be.false;
+            });
+
+            it('should remove the request in progress for open operation',
                function() {
-        var data = {};
-        beforeEach(function() {
-          data[unpacker.request.Key.OPEN_REQUEST_ID] = OPEN_REQUEST_ID;
-          decompressor.processMessage(
-              data, unpacker.request.Operation.CLOSE_FILE_DONE,
-              CLOSE_REQUEST_ID);
-        });
+                 expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
+                     .to.be.undefined;
+               });
 
-        it('should call onSuccess once', function() {
-          expect(onSuccessSpy.calledOnce).to.be.true;
-        });
-
-        it('should not call onError', function() {
-          expect(onErrorSpy.called).to.be.false;
-        });
-
-        it('should remove the request in progress for open operation',
-            function() {
-          expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
-              .to.be.undefined;
-        });
-
-        it('should remove the request in progress for close operation',
-            function() {
-          expect(decompressor.requestsInProgress[CLOSE_REQUEST_ID])
-              .to.be.undefined;
-        });
-      });
+            it('should remove the request in progress for close operation',
+               function() {
+                 expect(decompressor.requestsInProgress[CLOSE_REQUEST_ID])
+                     .to.be.undefined;
+               });
+          });
     });  // Test closeFile.
 
     // Test readFile.
@@ -317,8 +317,9 @@
         onSuccessSpy = sinon.spy();
         onErrorSpy = sinon.spy();
 
-        decompressor.readFile(READ_REQUEST_ID, OPEN_REQUEST_ID, OFFSET,
-                              LENGTH, onSuccessSpy, onErrorSpy);
+        decompressor.readFile(
+            READ_REQUEST_ID, OPEN_REQUEST_ID, OFFSET, LENGTH, onSuccessSpy,
+            onErrorSpy);
       });
 
       it('should add a new read request in progress', function() {
@@ -352,26 +353,26 @@
           });
 
           it('should call onSuccess with file data and hasMore as true',
-              function() {
-            expect(onSuccessSpy.calledWith('data', true)).to.be.true;
-          });
+             function() {
+               expect(onSuccessSpy.calledWith('data', true)).to.be.true;
+             });
 
           it('should not call onError', function() {
             expect(onErrorSpy.called).to.be.false;
           });
 
           it('should NOT remove the request in progress for open operation',
-              function() {
-            expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
-                .to.not.be.undefined;
-          });
+             function() {
+               expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
+                   .to.not.be.undefined;
+             });
 
           it('should NOT remove the request in progress for read operation',
-              function() {
-            // decompressor will still receive READ_FILE_DONE.
-            expect(decompressor.requestsInProgress[READ_REQUEST_ID])
-                .to.not.be.undefined;
-          });
+             function() {
+               // decompressor will still receive READ_FILE_DONE.
+               expect(decompressor.requestsInProgress[READ_REQUEST_ID])
+                   .to.not.be.undefined;
+             });
         });
 
         describe('that doesn\'t have any more data to read', function() {
@@ -385,28 +386,28 @@
           });
 
           it('should call onSuccess with file data and hasMore as false',
-              function() {
-            expect(onSuccessSpy.calledWith('data', false)).to.be.true;
-          });
+             function() {
+               expect(onSuccessSpy.calledWith('data', false)).to.be.true;
+             });
 
           it('should not call onError', function() {
             expect(onErrorSpy.called).to.be.false;
           });
 
           it('should NOT remove the request in progress for open operation',
-              function() {
-            expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
-                .to.not.be.undefined;
-          });
+             function() {
+               expect(decompressor.requestsInProgress[OPEN_REQUEST_ID])
+                   .to.not.be.undefined;
+             });
 
           it('should remove the request in progress for read operation',
-              function() {
-            // Last call, so it should be removed.
-            expect(decompressor.requestsInProgress[READ_REQUEST_ID])
-                .to.be.undefined;
-          });
+             function() {
+               // Last call, so it should be removed.
+               expect(decompressor.requestsInProgress[READ_REQUEST_ID])
+                   .to.be.undefined;
+             });
         });
       });  // Test READ_FILE_DONE.
-    });  // Test readFile.
-  });  // Test openFile.
+    });    // Test readFile.
+  });      // Test openFile.
 });
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js
similarity index 66%
rename from ui/file_manager/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js
index e1ebaca..8f71984 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_specific_archives_tests.js
@@ -125,14 +125,18 @@
       .to.deep.equal(expectedEntryMetadata.modificationTime);
 
   if (entryMetadata.isDirectory) {
-    expect(Object.keys(entryMetadata).length,
-           'Invalid number of entries for ' + name)
+    expect(
+        Object.keys(entryMetadata).length,
+        'Invalid number of entries for ' + name)
         .to.equal(Object.keys(expectedEntryMetadata).length);
 
     for (var childEntryName in expectedEntryMetadata.entries) {
-      expect(entryMetadata.entries[childEntryName],
-             'Invalid entry in directory ' + name).to.not.be.undefined;
-      testMetadata(entryMetadata.entries[childEntryName],
+      expect(
+          entryMetadata.entries[childEntryName],
+          'Invalid entry in directory ' + name)
+          .to.not.be.undefined;
+      testMetadata(
+          entryMetadata.entries[childEntryName],
           expectedEntryMetadata.entries[childEntryName]);
     }
   }
@@ -147,47 +151,53 @@
  *     the file to read.
  * @param {!unpacker.types.RequestId} readRequestId The read request id.
  */
-var testReadFile = function(fileSystemId, filePath, openRequestId,
-                            readRequestId) {
+var testReadFile = function(
+    fileSystemId, filePath, openRequestId, readRequestId) {
   var expectedBuffer;
 
   beforeEach(function(done) {
     var promise = tests_helper.getAndReadFileBlobPromise(
         SMALL_ARCHIVE_PATH_PREFIX + filePath);
 
-    promise.then(function(buffer) {
-      expectedBuffer = buffer;
-      done();
-    }).catch(test_utils.forceFailure);
+    promise
+        .then(function(buffer) {
+          expectedBuffer = buffer;
+          done();
+        })
+        .catch(test_utils.forceFailure);
   });
 
   it('should read the whole file', function(done) {
     var offset = 0;
     var length = Math.floor(expectedBuffer.length / 2);
-    var left_length;
+    var leftLength;
     var promise = tests_helper.createReadFilePromise(
         fileSystemId, readRequestId, openRequestId, offset, length);
 
-    promise.then(function(receivedBuffer) {
-      // It is possible tha receivedBuffer.length is different from length.
-      // This scenario is plausible in case length is really big, but we
-      // requested a small chunk so we should receive the same amount of
-      // data.
-      expect(receivedBuffer.length).to.equal(length);
-      expect(receivedBuffer).to.deep.equal(
-          expectedBuffer.subarray(offset, offset + length));
+    promise
+        .then(function(receivedBuffer) {
+          // It is possible tha receivedBuffer.length is different from length.
+          // This scenario is plausible in case length is really big, but we
+          // requested a small chunk so we should receive the same amount of
+          // data.
+          expect(receivedBuffer.length).to.equal(length);
+          expect(receivedBuffer)
+              .to.deep.equal(expectedBuffer.subarray(offset, offset + length));
 
-      // Get the last chunk of data.
-      offset += length;
-      left_length = expectedBuffer.length - receivedBuffer.length;
-      return tests_helper.createReadFilePromise(
-          fileSystemId, readRequestId, openRequestId, offset, left_length);
-    }).then(function(receivedBuffer) {
-      expect(receivedBuffer.length).to.equal(left_length);
-      expect(receivedBuffer).to.deep.equal(
-          expectedBuffer.subarray(offset, offset + left_length));
-      done();
-    }).catch(test_utils.forceFailure);
+          // Get the last chunk of data.
+          offset += length;
+          leftLength = expectedBuffer.length - receivedBuffer.length;
+          return tests_helper.createReadFilePromise(
+              fileSystemId, readRequestId, openRequestId, offset, leftLength);
+        })
+        .then(function(receivedBuffer) {
+          expect(receivedBuffer.length).to.equal(leftLength);
+          expect(receivedBuffer)
+              .to.deep.equal(
+                  expectedBuffer.subarray(offset, offset + leftLength));
+          done();
+        })
+        .catch(test_utils.forceFailure);
   });
 
   it('should read middle chunk from file', function(done) {
@@ -196,12 +206,14 @@
     var promise = tests_helper.createReadFilePromise(
         fileSystemId, readRequestId, openRequestId, offset, length);
 
-    promise.then(function(receivedBuffer) {
-      expect(receivedBuffer.length).to.equal(length);
-      expect(receivedBuffer).to.deep.equal(
-          expectedBuffer.subarray(offset, offset + length));
-      done();
-    }).catch(test_utils.forceFailure);
+    promise
+        .then(function(receivedBuffer) {
+          expect(receivedBuffer.length).to.equal(length);
+          expect(receivedBuffer)
+              .to.deep.equal(expectedBuffer.subarray(offset, offset + length));
+          done();
+        })
+        .catch(test_utils.forceFailure);
   });
 };
 
@@ -214,53 +226,57 @@
  * @param {!unpacker.types.RequestId} readRequestId The read request id.
  * @param {!unpacker.types.RequestId} closeRequestId The close request id.
  */
-var testOpenReadClose = function(fileSystemId, expectedMetadata, filePath,
-                                 openRequestId, readRequestId, closeRequestId) {
+var testOpenReadClose = function(
+    fileSystemId, expectedMetadata, filePath, openRequestId, readRequestId,
+    closeRequestId) {
   // Test onOpenFileRequested.
-  describe('and then opens file <' + filePath + '> for <' + fileSystemId + '>',
+  describe(
+      'and then opens file <' + filePath + '> for <' + fileSystemId + '>',
+      function() {
+        var mountProcessCounterBefore;
+
+        beforeEach(function(done) {
+          var options = {
+            fileSystemId: fileSystemId,
+            mode: 'READ',
+            create: false,
+            filePath: filePath,
+            requestId: openRequestId
+          };
+          mountProcessCounterBefore = unpacker.app.mountProcessCounter;
+          unpacker.app.onOpenFileRequested(
+              options, done, test_utils.forceFailure);
+        });
+
+        // Test mountProcessCounter for onOpenFileRequested.
+        it('should have the same mountProcessCounter value before and after ' +
+               'onOpenFileRequested call',
            function() {
-    var mountProcessCounterBefore;
+             expect(mountProcessCounterBefore)
+                 .to.equal(unpacker.app.mountProcessCounter);
+           });
 
-    beforeEach(function(done) {
-      var options = {
-        fileSystemId: fileSystemId,
-        mode: 'READ',
-        create: false,
-        filePath: filePath,
-        requestId: openRequestId
-      };
-      mountProcessCounterBefore = unpacker.app.mountProcessCounter;
-      unpacker.app.onOpenFileRequested(options, done, test_utils.forceFailure);
-    });
+        it('should load the volume metadata', function() {
+          testMetadata(
+              unpacker.app.volumes[fileSystemId].metadata, expectedMetadata);
+        });
 
-    // Test mountProcessCounter for onOpenFileRequested.
-    it('should have the same mountProcessCounter value before and after ' +
-       'onOpenFileRequested call',
-        function() {
-            expect(mountProcessCounterBefore)
-                .to.equal(unpacker.app.mountProcessCounter);
-    });
+        // Test read file operation.
+        describe('to read file contents of ' + filePath, function() {
+          testReadFile(fileSystemId, filePath, openRequestId, readRequestId);
+        });
 
-    it('should load the volume metadata', function() {
-      testMetadata(unpacker.app.volumes[fileSystemId].metadata,
-                   expectedMetadata);
-    });
-
-    // Test read file operation.
-    describe('to read file contents of ' + filePath, function() {
-      testReadFile(fileSystemId, filePath, openRequestId, readRequestId);
-    });
-
-    // Clean resources.
-    afterEach(function(done) {
-      var options = {
-        fileSystemId: fileSystemId,
-        requestId: closeRequestId,
-        openRequestId: openRequestId
-      };
-      unpacker.app.onCloseFileRequested(options, done, test_utils.forceFailure);
-    });
-  });
+        // Clean resources.
+        afterEach(function(done) {
+          var options = {
+            fileSystemId: fileSystemId,
+            requestId: closeRequestId,
+            openRequestId: openRequestId
+          };
+          unpacker.app.onCloseFileRequested(
+              options, done, test_utils.forceFailure);
+        });
+      });
 };
 
 /**
@@ -269,8 +285,8 @@
  * @param {!Object} expectedMetadata The volume's expected metadata.
  * @param {boolean} restore True if this is a request after restoring state.
  * @param {?string} passphrase Passphrase for encrypted archives. NULL
-*     otherwise.
-*/
+ *     otherwise.
+ */
 var smallArchiveCheck = function(
     fileSystemId, expectedMetadata, restore, passphrase) {
   var suffix = 'for <' + fileSystemId + '>';
@@ -281,8 +297,8 @@
       expect(unpacker.app.volumes[fileSystemId]).to.be.undefined;
     if (passphrase !== null) {
       // Simulate entering a wrong password twice until the correct one.
-      var factory = new PassphraseAppWindowFactory(
-          ['wrong-password', '', passphrase]);
+      var factory =
+          new PassphraseAppWindowFactory(['wrong-password', '', passphrase]);
       tests_helper.createAppWindow = factory.create.bind(factory);
     } else {
       tests_helper.createAppWindow = null;
@@ -322,15 +338,16 @@
     });
 
     // Test mountProcessCounter for onGetMetadataRequested.
-    it('should have the same mountProcessCounter value before and after the call',
-        function() {
-            expect(mountProcessCounterBefore)
-                .to.equal(unpacker.app.mountProcessCounter);
-    });
+    it('should have the same mountProcessCounter value before and after the ' +
+           'call',
+       function() {
+         expect(mountProcessCounterBefore)
+             .to.equal(unpacker.app.mountProcessCounter);
+       });
 
     it('should load the volume metadata', function() {
-      testMetadata(unpacker.app.volumes[fileSystemId].metadata,
-                   expectedMetadata);
+      testMetadata(
+          unpacker.app.volumes[fileSystemId].metadata, expectedMetadata);
     });
 
     it('should return correct metadata for all calls', function() {
@@ -363,15 +380,16 @@
     });
 
     // Test mountProcessCounter for onReadDirectoryRequested.
-    it('should have the same mountProcessCounter value before and after the call',
-        function() {
-            expect(mountProcessCounterBefore)
-                .to.equal(unpacker.app.mountProcessCounter);
-    });
+    it('should have the same mountProcessCounter value before and after the ' +
+           'call',
+       function() {
+         expect(mountProcessCounterBefore)
+             .to.equal(unpacker.app.mountProcessCounter);
+       });
 
     it('should load the volume metadata', function() {
-      testMetadata(unpacker.app.volumes[fileSystemId].metadata,
-                   expectedMetadata);
+      testMetadata(
+          unpacker.app.volumes[fileSystemId].metadata, expectedMetadata);
     });
 
     it('should load return the correct entries', function() {
@@ -399,13 +417,7 @@
  * @return {!Array<!fileSystemProvider.OpenFileRequestedOptions>}
  */
 var getOpenedFilesBeforeSuspend = function(fileSystemId) {
-  return [
-    {
-      openRequestId: 30,
-      filePath: '/file1',
-      mode: 'READ'
-    }
-  ];
+  return [{openRequestId: 30, filePath: '/file1', mode: 'READ'}];
 };
 
 /**
@@ -414,20 +426,19 @@
  * @param {!unpacker.types.FileSystemId} fileSystemId
  */
 var smallArchiveCheckAfterSuspend = function(fileSystemId) {
-  var openedFilesBeforeSuspend =
-      getOpenedFilesBeforeSuspend(fileSystemId);
+  var openedFilesBeforeSuspend = getOpenedFilesBeforeSuspend(fileSystemId);
 
   for (var i = 0; i < openedFilesBeforeSuspend.length; i++) {
     var openedFile = openedFilesBeforeSuspend[i];
     var openRequestId = openedFile.openRequestId;
-    var describeMessage =
-        'for <' + fileSystemId + '> and then reads contents of file <' +
-        openedFile.filePath + '> ' + 'opened before suspend page event,';
+    var describeMessage = 'for <' + fileSystemId +
+        '> and then reads contents of file <' + openedFile.filePath + '> ' +
+        'opened before suspend page event,';
 
     describe(describeMessage, function() {
       // Test read file.
-      testReadFile(fileSystemId, openedFile.filePath, openRequestId,
-                   openRequestId + 1);
+      testReadFile(
+          fileSystemId, openedFile.filePath, openRequestId, openRequestId + 1);
 
       // Clean resources.
       afterEach(function(done) {
@@ -437,8 +448,8 @@
           openRequestId: openRequestId
         };
 
-        unpacker.app.onCloseFileRequested(options, done,
-                                          test_utils.forceFailure);
+        unpacker.app.onCloseFileRequested(
+            options, done, test_utils.forceFailure);
       });
     });
   }
@@ -451,8 +462,7 @@
  * @param {!unpacker.types.FileSystemId} fileSystemId
  */
 var smallArchiveCheckAfterRestart = function(fileSystemId) {
-  var openedFilesBeforeSuspend =
-      getOpenedFilesBeforeSuspend(fileSystemId);
+  var openedFilesBeforeSuspend = getOpenedFilesBeforeSuspend(fileSystemId);
 
   for (var i = 0; i < openedFilesBeforeSuspend.length; i++) {
     var openedFile = openedFilesBeforeSuspend[i];
@@ -460,40 +470,40 @@
 
     describe('for <' + fileSystemId + '>', function() {
       it('and then tries to read contents of a previous opened file must fail',
-          function(done) {
-        var options = {
-          fileSystemId: fileSystemId,
-          requestId: openRequestId + 1,
-          openRequestId: openRequestId,
-          offset: 0,
-          length: 10
-        };
+         function(done) {
+           var options = {
+             fileSystemId: fileSystemId,
+             requestId: openRequestId + 1,
+             openRequestId: openRequestId,
+             offset: 0,
+             length: 10
+           };
 
-        unpacker.app.onReadFileRequested(
-            options, test_utils.forceFailure, function(error) {
-              setTimeout(function() {
-                expect(error).to.equal('INVALID_OPERATION');
-                done();
-              });
-            });
-      });
+           unpacker.app.onReadFileRequested(
+               options, test_utils.forceFailure, function(error) {
+                 setTimeout(function() {
+                   expect(error).to.equal('INVALID_OPERATION');
+                   done();
+                 });
+               });
+         });
 
       it('and then tries to close a previous opened file must fail',
-          function(done) {
-        var options = {
-          fileSystemId: fileSystemId,
-          requestId: openRequestId + 2,
-          openRequestId: openRequestId
-        };
+         function(done) {
+           var options = {
+             fileSystemId: fileSystemId,
+             requestId: openRequestId + 2,
+             openRequestId: openRequestId
+           };
 
-        unpacker.app.onCloseFileRequested(
-            options, test_utils.forceFailure, function(error) {
-              setTimeout(function() {
-                expect(error).to.equal('INVALID_OPERATION');
-                done();
-              });
-            });
-      });
+           unpacker.app.onCloseFileRequested(
+               options, test_utils.forceFailure, function(error) {
+                 setTimeout(function() {
+                   expect(error).to.equal('INVALID_OPERATION');
+                   done();
+                 });
+               });
+         });
     });
   }
 };
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/integration_test.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test.js
similarity index 83%
rename from ui/file_manager/zip_archiver/unpacker-test/js/integration_test.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test.js
index 032f5d7..5a6a311 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/integration_test.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test.js
@@ -20,7 +20,7 @@
 };
 
 // We need at least two zip files for all the tests to run correctly.
-var zip_list = [
+var zipList = [
   {
     name: 'small_zip.zip',
     afterOnLaunchTests: function() {
@@ -55,7 +55,7 @@
 ];
 
 // Init helper.
-var initPromise = tests_helper.init(zip_list);
+var initPromise = tests_helper.init(zipList);
 
 describe('The unpacker', function() {
   var mountProcessCounterBefore;
@@ -116,8 +116,8 @@
             done();
         },
         function(fileSystemId) {
-          tests_helper.forceFailure('Could not load volume <' + fileSystemId +
-                                    '>.');
+          tests_helper.forceFailure(
+              'Could not load volume <' + fileSystemId + '>.');
         });
   });
 
@@ -127,18 +127,19 @@
 
   // Check if volumes were correctly loaded.
   tests_helper.volumesInformation.forEach(function(volumeInformation) {
-    describe('that launches <' + volumeInformation.fileSystemId + '>',
-        function() {
+    describe(
+        'that launches <' + volumeInformation.fileSystemId + '>', function() {
           volumeInformation.afterOnLaunchTests();
         });
   });
 
   // Test mountProcessCounter for onLaunched.
-  it('should have the same mountProcessCounter before and after onLaunched call',
-      function() {
-          expect(mountProcessCounterBefore)
-              .to.equal(unpacker.app.mountProcessCounter);
-  });
+  it('should have the same mountProcessCounter before and after onLaunched ' +
+         'call',
+     function() {
+       expect(mountProcessCounterBefore)
+           .to.equal(unpacker.app.mountProcessCounter);
+     });
 
   // Test state save.
   describe('should save state in case of restarts or crashes', function() {
@@ -146,8 +147,8 @@
       expect(chrome.fileSystem.retainEntry.callCount)
           .to.equal(tests_helper.volumesInformation.length);
       tests_helper.volumesInformation.forEach(function(volume) {
-        expect(chrome.fileSystem.retainEntry.calledWith(volume.entry)).
-            to.be.true;
+        expect(chrome.fileSystem.retainEntry.calledWith(volume.entry))
+            .to.be.true;
       });
     });
 
@@ -246,9 +247,10 @@
         expect(unpacker.app.volumes[fileSystemId]).to.not.be.undefined;
         expect(tests_helper.localStorageState[storageKey][fileSystemId])
             .to.not.be.undefined;
-        unpacker.app.onUnmountRequested({fileSystemId: fileSystemId},
-                                        function() { done(); },
-                                        tests_helper.forceFailure);
+        unpacker.app.onUnmountRequested(
+            {fileSystemId: fileSystemId}, function() {
+              done();
+            }, tests_helper.forceFailure);
       });
 
       it('should remove volume from unpacker.app.volumes', function() {
@@ -269,41 +271,45 @@
 
   // Check if NaCL module is NOT unloaded when one volume is unloaded and
   // Zip Unpacker still has other mounted volumes.
-  describe('that unmounts a volume and still has unmounted volumes', function() {
-    beforeEach(function(done) {
-      // We need at least 2 zip files mounted to run this test.
-      expect(tests_helper.volumesInformation.length >= 2).to.be.true;
-      // Only unload the first volume.
-      var volumeInformation = tests_helper.volumesInformation[0];
-      var fileSystemId = volumeInformation.fileSystemId;
-      tests_helper.initChromeApis();
-      unpacker.app.onUnmountRequested({fileSystemId: fileSystemId}, function() {
-        // Make sure that there is at least one volume that is not unmounted.
-        expect(Object.keys(unpacker.app.volumes).length > 0).to.be.true;
-        done();
-      }.bind(this), tests_helper.forceFailure);
-    });
+  describe(
+      'that unmounts a volume and still has unmounted volumes', function() {
+        beforeEach(function(done) {
+          // We need at least 2 zip files mounted to run this test.
+          expect(tests_helper.volumesInformation.length >= 2).to.be.true;
+          // Only unload the first volume.
+          var volumeInformation = tests_helper.volumesInformation[0];
+          var fileSystemId = volumeInformation.fileSystemId;
+          tests_helper.initChromeApis();
+          unpacker.app.onUnmountRequested(
+              {fileSystemId: fileSystemId}, function() {
+                // Make sure that there is at least one volume that is not
+                // unmounted.
+                expect(Object.keys(unpacker.app.volumes).length > 0).to.be.true;
+                done();
+              }.bind(this), tests_helper.forceFailure);
+        });
 
-    it('should not unload the NaCL module', function() {
-      expect(unpacker.app.naclModule).to.not.be.null;
-      expect(unpacker.app.moduleLoadedPromise).to.not.be.null;
-    });
-  });
+        it('should not unload the NaCL module', function() {
+          expect(unpacker.app.naclModule).to.not.be.null;
+          expect(unpacker.app.moduleLoadedPromise).to.not.be.null;
+        });
+      });
 
   // Check if NaCL module is unloaded after all the volumes are unloaded.
   describe('that unmounts all the volumes', function() {
     beforeEach(function(done) {
       // The number of mounted volumes.
-      var volumeListSize = zip_list.length;
+      var volumeListSize = zipList.length;
       tests_helper.volumesInformation.forEach(function(volumeInformation) {
         var fileSystemId = volumeInformation.fileSystemId;
         tests_helper.initChromeApis();
-        unpacker.app.onUnmountRequested({fileSystemId: fileSystemId}, function() {
-          // Wait for all the volumes to be unloaded.
-          volumeListSize--;
-          if (volumeListSize == 0)
-            done();
-        }, tests_helper.forceFailure);
+        unpacker.app.onUnmountRequested(
+            {fileSystemId: fileSystemId}, function() {
+              // Wait for all the volumes to be unloaded.
+              volumeListSize--;
+              if (volumeListSize == 0)
+                done();
+            }, tests_helper.forceFailure);
       });
     });
 
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/integration_test_helper.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test_helper.js
similarity index 81%
rename from ui/file_manager/zip_archiver/unpacker-test/js/integration_test_helper.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test_helper.js
index 471b185..54e38a5 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/integration_test_helper.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/integration_test_helper.js
@@ -7,7 +7,7 @@
 /**
  * A helper namespace used by integration_tests.js.
  */
-var tests_helper = {
+var testsHelper = {
   /**
    * The base URL where all test archives are located.
    * @private {string}
@@ -54,31 +54,34 @@
    *     with the download failure error.
    */
   getFileBlob: function(filePath) {
-    if (tests_helper.fileBlobCache_[filePath])
-      return Promise.resolve(tests_helper.fileBlobCache_[filePath]);
+    if (testsHelper.fileBlobCache_[filePath])
+      return Promise.resolve(testsHelper.fileBlobCache_[filePath]);
 
     return new Promise(function(fulfill, reject) {
-      var xhr = new XMLHttpRequest();
-      xhr.open('GET', tests_helper.TEST_FILES_BASE_URL_ + filePath);
-      xhr.responseType = 'blob';
+             var xhr = new XMLHttpRequest();
+             xhr.open('GET', testsHelper.TEST_FILES_BASE_URL_ + filePath);
+             xhr.responseType = 'blob';
 
-      xhr.onload = fulfill.bind(null, xhr);
+             xhr.onload = fulfill.bind(null, xhr);
 
-      xhr.onerror = reject.bind(null, xhr);
+             xhr.onerror = reject.bind(null, xhr);
 
-      xhr.send(null);
-    }).then(function(xhr) {
-      if (xhr.readyState === 4) {
-        if (xhr.status === 200) {
-          tests_helper.fileBlobCache_[filePath] = xhr.response;
-          return xhr.response;  // The blob.
-        } else {
-          return Promise.reject(xhr.statusText + ': ' + filePath);
-        }
-      }
-    }, function(xhr) {
-      return Promise.reject(xhr.statusText + ': ' + filePath);
-    });
+             xhr.send(null);
+           })
+        .then(
+            function(xhr) {
+              if (xhr.readyState === 4) {
+                if (xhr.status === 200) {
+                  testsHelper.fileBlobCache_[filePath] = xhr.response;
+                  return xhr.response;  // The blob.
+                } else {
+                  return Promise.reject(xhr.statusText + ': ' + filePath);
+                }
+              }
+            },
+            function(xhr) {
+              return Promise.reject(xhr.statusText + ': ' + filePath);
+            });
   },
 
   /**
@@ -89,7 +92,7 @@
    *     or rejects with any received error.
    */
   getAndReadFileBlobPromise: function(filePath) {
-    return tests_helper.getFileBlob(filePath).then(function(blob) {
+    return testsHelper.getFileBlob(filePath).then(function(blob) {
       return new Promise(function(fulfill, reject) {
         var fileReader = new FileReader();
         fileReader.onload = function(event) {
@@ -120,17 +123,17 @@
 
     sinon.stub(chrome.storage.local, 'set', function(state, opt_successfulSet) {
       // Save the state in the local storage in a different memory.
-      tests_helper.localStorageState = JSON.parse(JSON.stringify(state));
+      testsHelper.localStorageState = JSON.parse(JSON.stringify(state));
       if (opt_successfulSet)
         opt_successfulSet();
     });
 
     sinon.stub(chrome.storage.local, 'get', function(state, onSuccess) {
-      // Make a deep copy as tests_helper.localStorageState is the data on the
+      // Make a deep copy as testsHelper.localStorageState is the data on the
       // local storage and not in memory. This way the extension will work on a
       // different memory which is the case in real scenarios.
       var localStorageState =
-          JSON.parse(JSON.stringify(tests_helper.localStorageState));
+          JSON.parse(JSON.stringify(testsHelper.localStorageState));
       onSuccess(localStorageState);
     });
 
@@ -141,7 +144,7 @@
       getDisplayPath: sinon.stub()
     };
 
-    tests_helper.volumesInformation.forEach(function(volume) {
+    testsHelper.volumesInformation.forEach(function(volume) {
       chrome.fileSystem.retainEntry.withArgs(volume.entry)
           .returns(volume.entryId);
       chrome.fileSystem.restoreEntry.withArgs(volume.entryId)
@@ -159,8 +162,8 @@
       mount: sinon.stub(),
       unmount: sinon.stub(),
       get: function(fileSystemId, callback) {
-        var volumeInfoList = tests_helper.volumesInformation.filter(
-            function(volumeInfo) {
+        var volumeInfoList =
+            testsHelper.volumesInformation.filter(function(volumeInfo) {
               return volumeInfo.fileSystemId == fileSystemId;
             });
         if (volumeInfoList.length == 0)
@@ -169,16 +172,17 @@
           callback(volumeInfoList[0].fileSystemMetadata);
       },
       getAll: sinon.stub().callsArgWith(
-          0,
-          tests_helper.volumesInformation.map(function(volumeInfo) {
+          0, testsHelper.volumesInformation.map(function(volumeInfo) {
             return volumeInfo.fileSystemMetadata;
           }))
     };
-    tests_helper.volumesInformation.forEach(function(volume) {
+    testsHelper.volumesInformation.forEach(function(volume) {
       chrome.fileSystemProvider.mount
-          .withArgs({fileSystemId: volume.fileSystemId,
-                     displayName: volume.entry.name,
-                     openedFilesLimit: 1})
+          .withArgs({
+            fileSystemId: volume.fileSystemId,
+            displayName: volume.entry.name,
+            openedFilesLimit: 1
+          })
           .callsArg(1);
       chrome.fileSystemProvider.unmount
           .withArgs({fileSystemId: volume.fileSystemId})
@@ -192,16 +196,11 @@
       // Contains 'lastError' property which is checked in case
       // chrome.fileSystem.restoreEntry fails. By default 'lastError' should be
       // undefined as no error is returned.
-      getManifest: sinon.stub().returns({
-        icons: {}
-      })
+      getManifest: sinon.stub().returns({icons: {}})
     };
 
     // Chrome notifications API.
-    chrome.notifications = {
-      create: sinon.stub(),
-      clear: sinon.stub()
-    };
+    chrome.notifications = {create: sinon.stub(), clear: sinon.stub()};
 
     // Chrome i18n API.
     chrome.i18n = {
@@ -210,9 +209,7 @@
     };
 
     // Chrome app window API. Used for the passphrase dialog only.
-    chrome.app.window = {
-      create: tests_helper.createAppWindow
-    };
+    chrome.app.window = {create: testsHelper.createAppWindow};
   },
 
   /**
@@ -231,10 +228,10 @@
     // Create promises to obtain archives blob.
     return Promise.all(archivesToTest.map(function(archiveData) {
       // Inititialization is done outside of the promise in order for Mocha to
-      // correctly identify the number of tests_helper.volumesInformation when
+      // correctly identify the number of testsHelper.volumesInformation when
       // it initialiazes tests. In case this is done in the promise, Mocha
       // will think there is no volumeInformation because at the time the
-      // JavaScript test file is parssed tests_helper.volumesInformation will
+      // JavaScript test file is parssed testsHelper.volumesInformation will
       // still be empty.
       var fileSystemId = archiveData.name;
 
@@ -283,9 +280,9 @@
         }
       };
 
-      tests_helper.volumesInformation.push(volumeInformation);
+      testsHelper.volumesInformation.push(volumeInformation);
 
-      return tests_helper.getFileBlob(archiveData.name).then(function(blob) {
+      return testsHelper.getFileBlob(archiveData.name).then(function(blob) {
         volumeInformation.entry.file = sinon.stub().callsArgWith(0, blob);
       });
     }));
@@ -302,8 +299,8 @@
    *     Int8Array buffer containing the requested data or rejects with
    *     ProviderError.
    */
-  createReadFilePromise: function(fileSystemId, readRequestId, openRequestId,
-                                  offset, length) {
+  createReadFilePromise: function(
+      fileSystemId, readRequestId, openRequestId, offset, length) {
     var options = {
       fileSystemId: fileSystemId,
       requestId: readRequestId,
diff --git a/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/passphrase_manager_test.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/passphrase_manager_test.js
new file mode 100644
index 0000000..b020599d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/passphrase_manager_test.js
@@ -0,0 +1,162 @@
+// 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.
+
+'use strict';
+
+describe('PassphraseManager', function() {
+  var passphraseWindow = null;
+  var passphraseWindowLoadCallback = null;
+
+  beforeEach(function() {
+    // This API is not available in Karma unit tests, so stub it using
+    // window.open.
+    chrome.app.window = {
+      create: function(url, options, callback) {
+        var closeCallbacks = [];
+        passphraseWindow = window.open(url);
+        passphraseWindow.onload = function() {
+          passphraseWindow.onEverythingLoaded = function() {
+            if (passphraseWindowLoadCallback)
+              passphraseWindowLoadCallback();
+          };
+          passphraseWindow.onunload = function() {
+            closeCallbacks.forEach(function(callback) {
+              callback();
+            });
+          };
+        };
+        callback({
+          contentWindow: passphraseWindow,
+          onClosed: {
+            addListener: function(onClosedCallback) {
+              closeCallbacks.push(onClosedCallback);
+            }
+          }
+        });
+      }
+    };
+  });
+
+  describe('that has an initial passphrase', function() {
+    var TEST_PASSPHRASE = 'hello-world';
+    var passphraseManager = new unpacker.PassphraseManager(TEST_PASSPHRASE);
+
+    afterEach(function() {
+      passphraseWindowLoadCallback = null;
+      if (passphraseWindow)
+        passphraseWindow.close();
+      passphraseWindow = null;
+    });
+
+    it('should return it immediately', function(done) {
+      passphraseManager.getPassphrase()
+          .then(function(passphrase) {
+            expect(passphrase).to.equal(TEST_PASSPHRASE);
+            expect(passphraseManager.rememberedPassphrase)
+                .to.equal(TEST_PASSPHRASE);
+            done();
+          })
+          .catch(test_utils.forceFailure);
+    });
+
+    it('should not return it again for the second call', function(done) {
+      passphraseWindowLoadCallback = function() {
+        // Close the window as soon as it's loaded.
+        passphraseWindow.close();
+      };
+      passphraseManager.getPassphrase()
+          .then(test_utils.forceFailure)
+          .catch(function(error) {
+            expect(error).to.equal('FAILED');
+            done();
+          });
+    });
+  });
+
+  describe('without an initial passphrase', function() {
+    var USER_PASSPHRASE = 'hello-kitty';
+    var passphraseManager = new unpacker.PassphraseManager(null);
+
+    afterEach(function() {
+      passphraseWindowLoadCallback = null;
+      if (passphraseWindow)
+        passphraseWindow.close();
+      passphraseWindow = null;
+    });
+
+    it('should accept a passphrase from a user with remembering',
+       function(done) {
+         passphraseWindowLoadCallback = function() {
+           // Fill out the password field and close the dialog as soon as it's
+           // loaded.
+           passphraseWindow.document.querySelector('html /deep/ #input').value =
+               USER_PASSPHRASE;
+           passphraseWindow.document.querySelector('html /deep/ #remember')
+               .checked = true;
+           passphraseWindow.document.querySelector('html /deep/ #acceptButton')
+               .click();
+         };
+         passphraseManager.getPassphrase()
+             .then(function(passphrase) {
+               expect(passphrase).to.equal(USER_PASSPHRASE);
+               expect(passphraseManager.rememberedPassphrase)
+                   .to.equal(USER_PASSPHRASE);
+               done();
+             })
+             .catch(test_utils.forceFailure);
+       });
+
+    it('should accept a passphrase from a user without remembering',
+       function(done) {
+         passphraseWindowLoadCallback = function() {
+           // Fill out the password field and close the dialog as soon as it's
+           // loaded.
+           passphraseWindow.document.querySelector('html /deep/ #input').value =
+               USER_PASSPHRASE;
+           passphraseWindow.document.querySelector('html /deep/ #acceptButton')
+               .click();
+         };
+         passphraseManager.getPassphrase()
+             .then(function(passphrase) {
+               expect(passphrase).to.equal(USER_PASSPHRASE);
+               expect(passphraseManager.rememberedPassphrase).to.be.null;
+               done();
+             })
+             .catch(test_utils.forceFailure);
+       });
+
+    it('should reject password on window cancel button', function(done) {
+      passphraseWindowLoadCallback = function() {
+        passphraseWindow.document.querySelector('html /deep/ #input').value =
+            USER_PASSPHRASE;
+        passphraseWindow.document.querySelector('html /deep/ #remember')
+            .checked = true;
+        passphraseWindow.document.querySelector('html /deep/ #cancelButton')
+            .click();
+      };
+      passphraseManager.getPassphrase().then(
+          test_utils.forceFailure, function(error) {
+            expect(error).to.equal('FAILED');
+            expect(passphraseManager.rememberedPassphrase).to.be.null;
+            done();
+          });
+    });
+
+    it('should reject password on window close', function(done) {
+      passphraseWindowLoadCallback = function() {
+        passphraseWindow.document.querySelector('html /deep/ #input').value =
+            USER_PASSPHRASE;
+        passphraseWindow.document.querySelector('html /deep/ #remember')
+            .checked = true;
+        passphraseWindow.close();
+      };
+      passphraseManager.getPassphrase().then(
+          test_utils.forceFailure, function(error) {
+            expect(error).to.equal('FAILED');
+            expect(passphraseManager.rememberedPassphrase).to.be.null;
+            done();
+          });
+    });
+  });
+});
diff --git a/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/request_test.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/request_test.js
new file mode 100644
index 0000000..30447cec
--- /dev/null
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/request_test.js
@@ -0,0 +1,284 @@
+// 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.
+
+'use strict';
+
+describe('On calling', function() {
+  /**
+   * @const {string}
+   */
+  var FILE_SYSTEM_ID = 'id';
+
+  /**
+   * @const {number}
+   */
+  var REQUEST_ID = 10;
+
+  /**
+   * @const {string}
+   */
+  var ENCODING = 'CP1250';
+
+  /**
+   * @const {number}
+   */
+  var ARCHIVE_SIZE = 5000;
+
+  /**
+   * @const {!ArrayBuffer}
+   */
+  var CHUNK_BUFFER = new ArrayBuffer(5);
+
+  /**
+   * @const {number}
+   */
+  var CHUNK_OFFSET = 150;
+
+  /**
+   * @const {string}
+   */
+  var CLOSE_VOLUME_REQUEST_ID = '-1';
+
+  /**
+   * @const {number}
+   */
+  var INDEX = 123;
+
+  /**
+   * @const {number}
+   */
+  var OPEN_REQUEST_ID = 7;
+
+  /**
+   * @const {number}
+   */
+  var OFFSET = 50;
+
+  /**
+   * @const {number}
+   */
+  var LENGTH = 200;
+
+  describe(
+      'request.createReadMetadataRequest should create a request', function() {
+        var readMetadataRequest;
+        beforeEach(function() {
+          readMetadataRequest = unpacker.request.createReadMetadataRequest(
+              FILE_SYSTEM_ID, REQUEST_ID, ENCODING, ARCHIVE_SIZE);
+        });
+
+        it('with READ_METADATA as operation', function() {
+          expect(readMetadataRequest[unpacker.request.Key.OPERATION])
+              .to.equal(unpacker.request.Operation.READ_METADATA);
+        });
+
+        it('with correct file system id', function() {
+          expect(readMetadataRequest[unpacker.request.Key.FILE_SYSTEM_ID])
+              .to.equal(FILE_SYSTEM_ID);
+        });
+
+        it('with correct request id', function() {
+          expect(readMetadataRequest[unpacker.request.Key.REQUEST_ID])
+              .to.equal(REQUEST_ID.toString());
+        });
+
+        it('with correct encoding', function() {
+          expect(readMetadataRequest[unpacker.request.Key.ENCODING])
+              .to.equal(ENCODING);
+        });
+
+        it('with correct archive size', function() {
+          expect(readMetadataRequest[unpacker.request.Key.ARCHIVE_SIZE])
+              .to.equal(ARCHIVE_SIZE.toString());
+        });
+      });
+
+  describe(
+      'request.createReadChunkDoneResponse should create a response',
+      function() {
+        var readChunkDoneReponse;
+        beforeEach(function() {
+          readChunkDoneReponse = unpacker.request.createReadChunkDoneResponse(
+              FILE_SYSTEM_ID, REQUEST_ID, CHUNK_BUFFER, CHUNK_OFFSET);
+        });
+
+        it('with READ_CHUNK_DONE as operation', function() {
+          expect(readChunkDoneReponse[unpacker.request.Key.OPERATION])
+              .to.equal(unpacker.request.Operation.READ_CHUNK_DONE);
+        });
+
+        it('with correct file system id', function() {
+          expect(readChunkDoneReponse[unpacker.request.Key.FILE_SYSTEM_ID])
+              .to.equal(FILE_SYSTEM_ID);
+        });
+
+        it('with correct request id', function() {
+          expect(readChunkDoneReponse[unpacker.request.Key.REQUEST_ID])
+              .to.equal(REQUEST_ID.toString());
+        });
+
+        it('with correct chunk buffer', function() {
+          expect(readChunkDoneReponse[unpacker.request.Key.CHUNK_BUFFER])
+              .to.equal(CHUNK_BUFFER);
+        });
+
+        it('with correct chunk offset', function() {
+          expect(readChunkDoneReponse[unpacker.request.Key.OFFSET])
+              .to.equal(CHUNK_OFFSET.toString());
+        });
+      });
+
+  describe(
+      'request.createReadChunkErrorResponse should create a response',
+      function() {
+        var readChunkErrorReponse;
+        beforeEach(function() {
+          readChunkErrorReponse = unpacker.request.createReadChunkErrorResponse(
+              FILE_SYSTEM_ID, REQUEST_ID, CHUNK_BUFFER);
+        });
+
+        it('with READ_CHUNK_ERROR as operation', function() {
+          expect(readChunkErrorReponse[unpacker.request.Key.OPERATION])
+              .to.equal(unpacker.request.Operation.READ_CHUNK_ERROR);
+        });
+
+        it('with correct file system id', function() {
+          expect(readChunkErrorReponse[unpacker.request.Key.FILE_SYSTEM_ID])
+              .to.equal(FILE_SYSTEM_ID);
+        });
+
+        it('with correct request id', function() {
+          expect(readChunkErrorReponse[unpacker.request.Key.REQUEST_ID])
+              .to.equal(REQUEST_ID.toString());
+        });
+      });
+
+  describe(
+      'request.createCloseVolumeRequest should create a request', function() {
+        var closeVolumeRequest;
+        beforeEach(function() {
+          closeVolumeRequest =
+              unpacker.request.createCloseVolumeRequest(FILE_SYSTEM_ID);
+        });
+
+        it('with CLOSE_VOLUME as operation', function() {
+          expect(closeVolumeRequest[unpacker.request.Key.OPERATION])
+              .to.equal(unpacker.request.Operation.CLOSE_VOLUME);
+        });
+
+        it('with correct file system id', function() {
+          expect(closeVolumeRequest[unpacker.request.Key.FILE_SYSTEM_ID])
+              .to.equal(FILE_SYSTEM_ID);
+        });
+
+        it('with correct request id', function() {
+          expect(closeVolumeRequest[unpacker.request.Key.REQUEST_ID])
+              .to.equal(CLOSE_VOLUME_REQUEST_ID);
+        });
+      });
+
+  describe('request.createOpenFileRequest should create a request', function() {
+    var openFileRequest;
+    beforeEach(function() {
+      openFileRequest = unpacker.request.createOpenFileRequest(
+          FILE_SYSTEM_ID, REQUEST_ID, INDEX, ENCODING, ARCHIVE_SIZE);
+    });
+
+    it('with OPEN_FILE as operation', function() {
+      expect(openFileRequest[unpacker.request.Key.OPERATION])
+          .to.equal(unpacker.request.Operation.OPEN_FILE);
+    });
+
+    it('with correct file system id', function() {
+      expect(openFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
+          .to.equal(FILE_SYSTEM_ID);
+    });
+
+    it('with correct request id', function() {
+      expect(openFileRequest[unpacker.request.Key.REQUEST_ID])
+          .to.equal(REQUEST_ID.toString());
+    });
+
+    it('with correct file path', function() {
+      expect(openFileRequest[unpacker.request.Key.INDEX])
+          .to.equal(INDEX.toString());
+    });
+
+    it('with correct encoding', function() {
+      expect(openFileRequest[unpacker.request.Key.ENCODING]).to.equal(ENCODING);
+    });
+
+    it('with correct archive size', function() {
+      expect(openFileRequest[unpacker.request.Key.ARCHIVE_SIZE])
+          .to.equal(ARCHIVE_SIZE.toString());
+    });
+  });
+
+  describe(
+      'request.createCloseFileRequest should create a request', function() {
+        var closeFileRequest;
+        beforeEach(function() {
+          closeFileRequest = unpacker.request.createCloseFileRequest(
+              FILE_SYSTEM_ID, REQUEST_ID, OPEN_REQUEST_ID);
+        });
+
+        it('with CLOSE_FILE as operation', function() {
+          expect(closeFileRequest[unpacker.request.Key.OPERATION])
+              .to.equal(unpacker.request.Operation.CLOSE_FILE);
+        });
+
+        it('with correct file system id', function() {
+          expect(closeFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
+              .to.equal(FILE_SYSTEM_ID);
+        });
+
+        it('with correct request id', function() {
+          expect(closeFileRequest[unpacker.request.Key.REQUEST_ID])
+              .to.equal(REQUEST_ID.toString());
+        });
+
+        it('with correct open request id', function() {
+          expect(closeFileRequest[unpacker.request.Key.OPEN_REQUEST_ID])
+              .to.equal(OPEN_REQUEST_ID.toString());
+        });
+      });
+
+  describe('request.createReadFileRequest should create a request', function() {
+    var readFileRequest;
+    beforeEach(function() {
+      readFileRequest = unpacker.request.createReadFileRequest(
+          FILE_SYSTEM_ID, REQUEST_ID, OPEN_REQUEST_ID, OFFSET, LENGTH);
+    });
+
+    it('with READ_FILE as operation', function() {
+      expect(readFileRequest[unpacker.request.Key.OPERATION])
+          .to.equal(unpacker.request.Operation.READ_FILE);
+    });
+
+    it('with correct file system id', function() {
+      expect(readFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
+          .to.equal(FILE_SYSTEM_ID);
+    });
+
+    it('with correct request id', function() {
+      expect(readFileRequest[unpacker.request.Key.REQUEST_ID])
+          .to.equal(REQUEST_ID.toString());
+    });
+
+    it('with correct open request id', function() {
+      expect(readFileRequest[unpacker.request.Key.OPEN_REQUEST_ID])
+          .to.equal(OPEN_REQUEST_ID.toString());
+    });
+
+    it('with correct offset', function() {
+      expect(readFileRequest[unpacker.request.Key.OFFSET])
+          .to.equal(OFFSET.toString());
+    });
+
+    it('with correct length', function() {
+      expect(readFileRequest[unpacker.request.Key.LENGTH])
+          .to.equal(LENGTH.toString());
+    });
+  });
+});
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/test_utils.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/test_utils.js
similarity index 96%
rename from ui/file_manager/zip_archiver/unpacker-test/js/test_utils.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/test_utils.js
index 14fbd31..be1771f04 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/test_utils.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/test_utils.js
@@ -7,7 +7,7 @@
 /**
  * Utility functions for all tests.
  */
-var test_utils = {
+var testUtils = {
   /**
    * Forces failure in tests. Should be called only from 'beforeEach',
    * 'afterEach' and 'it'. Useful to force failures in promises.
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/volume_test.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/volume_test.js
similarity index 79%
rename from ui/file_manager/zip_archiver/unpacker-test/js/volume_test.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/volume_test.js
index 96e7b42..c8c9ad6 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/js/volume_test.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/js/volume_test.js
@@ -37,11 +37,11 @@
         modificationTime: 12000 /* In seconds. */,
         entries: {
           'insideFile': {
-             index: 1,
-             name: 'insideFile',
-             size: 45,
-             isDirectory: false,
-             modificationTime: 200 /* In seconds. */
+            index: 1,
+            name: 'insideFile',
+            size: 45,
+            isDirectory: false,
+            modificationTime: 200 /* In seconds. */
           }
         }
       }
@@ -171,8 +171,8 @@
       });
 
       it('that has correct number of ms for modification time', function() {
-        expect(volume.metadata.modificationTime.getTime()).
-            to.equal(METADATA.modificationTime * 1000);
+        expect(volume.metadata.modificationTime.getTime())
+            .to.equal(METADATA.modificationTime * 1000);
       });
     });
 
@@ -192,8 +192,8 @@
       });
 
       it('that has correct number of ms for modification time', function() {
-        expect(volume.metadata.entries['file'].modificationTime.getTime()).
-            to.equal(METADATA.entries['file'].modificationTime * 1000);
+        expect(volume.metadata.entries['file'].modificationTime.getTime())
+            .to.equal(METADATA.entries['file'].modificationTime * 1000);
       });
     });
 
@@ -250,8 +250,8 @@
         });
 
         it('should call onSuccess with the entry metadata', function() {
-          expect(onSuccessSpy.calledWith(
-              volume.metadata.entries['dir'])).to.be.true;
+          expect(onSuccessSpy.calledWith(volume.metadata.entries['dir']))
+              .to.be.true;
         });
       });
 
@@ -268,7 +268,8 @@
 
         it('should call onSuccess with the entry metadata', function() {
           expect(onSuccessSpy.calledWith(
-              volume.metadata.entries['dir'].entries['insideFile'])).to.be.true;
+                     volume.metadata.entries['dir'].entries['insideFile']))
+              .to.be.true;
         });
       });
     });  // Test onGetMetadataRequested.
@@ -286,8 +287,7 @@
       describe('with invalid directoryPath', function() {
         beforeEach(function() {
           var options = {directoryPath: '/invalid'};
-          volume.onReadDirectoryRequested(options, onSuccessSpy,
-              onErrorSpy);
+          volume.onReadDirectoryRequested(options, onSuccessSpy, onErrorSpy);
         });
 
         it('should not call onSuccess', function() {
@@ -303,8 +303,7 @@
       describe('with a file that is not a directory', function() {
         beforeEach(function() {
           var options = {directoryPath: '/file'};
-          volume.onReadDirectoryRequested(options, onSuccessSpy,
-              onErrorSpy);
+          volume.onReadDirectoryRequested(options, onSuccessSpy, onErrorSpy);
         });
 
         it('should not call onSuccess', function() {
@@ -320,8 +319,7 @@
       describe('with a valid directory', function() {
         beforeEach(function() {
           var options = {directoryPath: '/'};
-          volume.onReadDirectoryRequested(options, onSuccessSpy,
-              onErrorSpy);
+          volume.onReadDirectoryRequested(options, onSuccessSpy, onErrorSpy);
         });
 
         it('should not call onError', function() {
@@ -329,14 +327,12 @@
         });
 
         it('should call onSuccess with the directory entries', function() {
-          var entries = [
-            volume.metadata.entries['file'],
-            volume.metadata.entries['dir']
-          ];
+          var entries =
+              [volume.metadata.entries['file'], volume.metadata.entries['dir']];
           expect(onSuccessSpy.calledWith(entries, false)).to.be.true;
         });
       });  // Valid directory.
-    });  // Test onReadDirectoryRequested.
+    });    // Test onReadDirectoryRequested.
 
     // Test onOpenFileRequested.
     describe('and calls onOpenFileRequested', function() {
@@ -388,8 +384,8 @@
             requestId: OPEN_REQUEST_ID,
             filePath: '/file'
           };
-          decompressor.openFile.withArgs(
-              options.requestId, INDEX, ENCODING).callsArg(3);
+          decompressor.openFile.withArgs(options.requestId, INDEX, ENCODING)
+              .callsArg(3);
 
           expect(volume.openedFiles[options.requestId]).to.be.undefined;
           volume.onOpenFileRequested(options, onSuccessSpy, onErrorSpy);
@@ -418,12 +414,8 @@
 
           describe('with invalid openRequestId', function() {
             beforeEach(function() {
-              var options = {
-                requestId: CLOSE_REQUEST_ID,
-                openRequestId: -1
-              };
-              volume.onCloseFileRequested(options, onSuccessSpy,
-                  onErrorSpy);
+              var options = {requestId: CLOSE_REQUEST_ID, openRequestId: -1};
+              volume.onCloseFileRequested(options, onSuccessSpy, onErrorSpy);
             });
 
             it('should call onError', function() {
@@ -444,11 +436,11 @@
                 requestId: CLOSE_REQUEST_ID,
                 openRequestId: OPEN_REQUEST_ID
               };
-              decompressor.closeFile.withArgs(
-                  options.requestId, options.openRequestId).callsArg(2);
+              decompressor.closeFile
+                  .withArgs(options.requestId, options.openRequestId)
+                  .callsArg(2);
 
-              volume.onCloseFileRequested(options, onSuccessSpy,
-                  onErrorSpy);
+              volume.onCloseFileRequested(options, onSuccessSpy, onErrorSpy);
             });
 
             it('should not call onError', function() {
@@ -460,11 +452,11 @@
             });
 
             it('should remove open operation options from openedFiles',
-                function() {
-              expect(volume.openedFiles[options.requestId]).to.be.undefined;
-            });
+               function() {
+                 expect(volume.openedFiles[options.requestId]).to.be.undefined;
+               });
           });  // Valid openRequestId.
-        });  // Test onCloseFileRequested.
+        });    // Test onCloseFileRequested.
 
         // Test onReadFileRequested.
         describe('and calls onReadFileRequested', function() {
@@ -513,10 +505,11 @@
             });
 
             it('should call onSuccess with empty buffer and no more data',
-                function() {
-              expect(onSuccessSpy.calledWith(
-                  new ArrayBuffer(0), false /* No more data. */)).to.be.true;
-            });
+               function() {
+                 expect(onSuccessSpy.calledWith(
+                            new ArrayBuffer(0), false /* No more data. */))
+                     .to.be.true;
+               });
           });
 
           // Offset equal to file size.
@@ -538,10 +531,11 @@
             });
 
             it('should call onSuccess with empty buffer and no more data',
-                function() {
-              expect(onSuccessSpy.calledWith(
-                  new ArrayBuffer(0), false /* No more data. */)).to.be.true;
-            });
+               function() {
+                 expect(onSuccessSpy.calledWith(
+                            new ArrayBuffer(0), false /* No more data. */))
+                     .to.be.true;
+               });
           });
 
           // Offset > file size.
@@ -563,10 +557,11 @@
             });
 
             it('should call onSuccess with empty buffer and no more data',
-                function() {
-              expect(onSuccessSpy.calledWith(
-                  new ArrayBuffer(0), false /* No more data. */)).to.be.true;
-            });
+               function() {
+                 expect(onSuccessSpy.calledWith(
+                            new ArrayBuffer(0), false /* No more data. */))
+                     .to.be.true;
+               });
           });
 
           // Offset 0 and length < file size.
@@ -578,9 +573,11 @@
                 offset: 0,
                 length: 1
               };
-              decompressor.readFile.withArgs(
-                  options.requestId, options.openRequestId, options.offset,
-                  options.length).callsArgWith(
+              decompressor.readFile
+                  .withArgs(
+                      options.requestId, options.openRequestId, options.offset,
+                      options.length)
+                  .callsArgWith(
                       4 /* onSuccessSpy. */, new ArrayBuffer(1), false);
 
               volume.onReadFileRequested(options, onSuccessSpy, onErrorSpy);
@@ -591,10 +588,11 @@
             });
 
             it('should call onSuccess with correct buffer and no more data',
-                function() {
-              expect(onSuccessSpy.calledWith(
-                  new ArrayBuffer(1), false /* No more data. */)).to.be.true;
-            });
+               function() {
+                 expect(onSuccessSpy.calledWith(
+                            new ArrayBuffer(1), false /* No more data. */))
+                     .to.be.true;
+               });
           });
 
           // Offset 0 and length > file size.
@@ -609,9 +607,11 @@
               };
 
               maxLength = METADATA.entries['file'].size;
-              decompressor.readFile.withArgs(
-                  options.requestId, options.openRequestId, options.offset,
-                  maxLength).callsArgWith(
+              decompressor.readFile
+                  .withArgs(
+                      options.requestId, options.openRequestId, options.offset,
+                      maxLength)
+                  .callsArgWith(
                       4 /* onSuccessSpy. */, new ArrayBuffer(maxLength), false);
 
               volume.onReadFileRequested(options, onSuccessSpy, onErrorSpy);
@@ -622,61 +622,63 @@
             });
 
             it('should call onSuccess with correct buffer and no more data',
-                function() {
-              expect(onSuccessSpy.calledWith(new ArrayBuffer(maxLength), false))
-                  .to.be.true;
-            });
+               function() {
+                 expect(
+                     onSuccessSpy.calledWith(new ArrayBuffer(maxLength), false))
+                     .to.be.true;
+               });
           });  // Offset 0 and length > file size.
-        });  // Test onReadFileRequested.
-      });  // Valid options.
-    });  // Test onOpenFileRequested.
+        });    // Test onReadFileRequested.
+      });      // Valid options.
+    });        // Test onOpenFileRequested.
 
     // Test onCloseFileRequested.
-    describe('and calls onCloseFileRequested before onOpenFileRequested',
-             function() {
-      var onSuccessSpy;
-      var onErrorSpy;
-      beforeEach(function() {
-        onSuccessSpy = sinon.spy();
-        onErrorSpy = sinon.spy();
-        var options = {
-          requestId: CLOSE_REQUEST_ID,
-          openRequestId: OPEN_REQUEST_ID
-        };
-        volume.onCloseFileRequested(options, onSuccessSpy, onErrorSpy);
-      });
+    describe(
+        'and calls onCloseFileRequested before onOpenFileRequested',
+        function() {
+          var onSuccessSpy;
+          var onErrorSpy;
+          beforeEach(function() {
+            onSuccessSpy = sinon.spy();
+            onErrorSpy = sinon.spy();
+            var options = {
+              requestId: CLOSE_REQUEST_ID,
+              openRequestId: OPEN_REQUEST_ID
+            };
+            volume.onCloseFileRequested(options, onSuccessSpy, onErrorSpy);
+          });
 
-      it('should not call onSuccess', function() {
-        expect(onSuccessSpy.called).to.be.false;
-      });
+          it('should not call onSuccess', function() {
+            expect(onSuccessSpy.called).to.be.false;
+          });
 
-      it('should call onError with INVALID_OPERATION', function() {
-        expect(onErrorSpy.calledWith('INVALID_OPERATION')).to.be.true;
-      });
-    });  // Test onCloseFileRequested.
+          it('should call onError with INVALID_OPERATION', function() {
+            expect(onErrorSpy.calledWith('INVALID_OPERATION')).to.be.true;
+          });
+        });  // Test onCloseFileRequested.
 
     // Test onReadFileRequested.
-    describe('and calls onReadFileRequested before onOpenFileRequested',
-             function() {
-      var onSuccessSpy;
-      var onErrorSpy;
-      beforeEach(function() {
-        onSuccessSpy = sinon.spy();
-        onErrorSpy = sinon.spy();
-        var options = {
-          requestId: READ_REQUEST_ID,
-          openRequestId: OPEN_REQUEST_ID
-        };
-        volume.onReadFileRequested(options, onSuccessSpy, onErrorSpy);
-      });
+    describe(
+        'and calls onReadFileRequested before onOpenFileRequested', function() {
+          var onSuccessSpy;
+          var onErrorSpy;
+          beforeEach(function() {
+            onSuccessSpy = sinon.spy();
+            onErrorSpy = sinon.spy();
+            var options = {
+              requestId: READ_REQUEST_ID,
+              openRequestId: OPEN_REQUEST_ID
+            };
+            volume.onReadFileRequested(options, onSuccessSpy, onErrorSpy);
+          });
 
-      it('should not call onSuccess', function() {
-        expect(onSuccessSpy.called).to.be.false;
-      });
+          it('should not call onSuccess', function() {
+            expect(onSuccessSpy.called).to.be.false;
+          });
 
-      it('should call the decompressor with correct request', function() {
-        expect(onErrorSpy.calledWith('INVALID_OPERATION')).to.be.true;
-      });
-    });  // Test onReadFileRequested.
-  });  // Valid metadata.
+          it('should call the decompressor with correct request', function() {
+            expect(onErrorSpy.calledWith('INVALID_OPERATION')).to.be.true;
+          });
+        });  // Test onReadFileRequested.
+  });        // Valid metadata.
 });
diff --git a/ui/file_manager/zip_archiver/unpacker-test/karma.conf.js b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/karma.conf.js
similarity index 96%
rename from ui/file_manager/zip_archiver/unpacker-test/karma.conf.js
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/karma.conf.js
index 464756be..62deb075 100644
--- a/ui/file_manager/zip_archiver/unpacker-test/karma.conf.js
+++ b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/karma.conf.js
@@ -51,8 +51,7 @@
       {pattern: 'module.pexe', watched: false, included: false, served: true},
       // unpacker.js served before as it contains the main namespace.
       {pattern: 'js/unpacker.js', watched: true, included: true, served: true},
-      {pattern: 'js/app.js', watched: true, included: true, served: true},
-      {
+      {pattern: 'js/app.js', watched: true, included: true, served: true}, {
         pattern: 'js/decompressor.js',
         watched: true,
         included: true,
@@ -147,16 +146,12 @@
       'Chrome-dev': {
         base: 'Chrome',
         flags: [
-          '--disable-setuid-sandbox',
-          '--enable-nacl',
-          '--enable-pnacl',
+          '--disable-setuid-sandbox', '--enable-nacl', '--enable-pnacl',
           '--user-data-dir=user-data-dir-karma',
           // Required for redirecting NaCl module stdout and stderr outputs
           // using NACL_EXE_STDOUT and NACL_EXE_STDERR environment variables.
           // See run_js_tests.js.
-          '--no-sandbox',
-          '--enable-logging',
-          '--v=1'
+          '--no-sandbox', '--enable-logging', '--v=1'
         ]
       }
     },
diff --git a/ui/file_manager/zip_archiver/unpacker-test/run_cpp_tests.sh b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/run_cpp_tests.sh
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/run_cpp_tests.sh
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/run_cpp_tests.sh
diff --git a/ui/file_manager/zip_archiver/unpacker-test/run_js_tests.sh b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/run_js_tests.sh
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/run_js_tests.sh
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/run_js_tests.sh
diff --git a/ui/file_manager/zip_archiver/unpacker-test/test-files/encrypted.zip b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/encrypted.zip
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/test-files/encrypted.zip
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/encrypted.zip
Binary files differ
diff --git a/ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/dir/file3 b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/dir/file3
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/dir/file3
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/dir/file3
diff --git a/ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/file1 b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/file1
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/file1
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/file1
diff --git a/ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/file2 b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/file2
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/test-files/small_archive/file2
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_archive/file2
diff --git a/ui/file_manager/zip_archiver/unpacker-test/test-files/small_zip.zip b/chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_zip.zip
similarity index 100%
rename from ui/file_manager/zip_archiver/unpacker-test/test-files/small_zip.zip
rename to chrome/browser/resources/chromeos/zip_archiver/unpacker-test/test-files/small_zip.zip
Binary files differ
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/md_bookmarks/toolbar.html b/chrome/browser/resources/md_bookmarks/toolbar.html
index 9f077ac..94911b0 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.html
+++ b/chrome/browser/resources/md_bookmarks/toolbar.html
@@ -64,9 +64,10 @@
     </cr-toolbar>
     <template is="cr-lazy-render" id="dropdown">
       <dialog is="cr-action-menu" role="menu">
-        <button class="dropdown-item"
+        <button id="sortButton"
+            class="dropdown-item"
             on-tap="onSortTap_"
-            disabled="[[!canChangeList_]]"
+            disabled="[[!canSortFolder_]]"
             role="menuitem">
           $i18n{menuSort}
         </button>
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.js b/chrome/browser/resources/md_bookmarks/toolbar.js
index 6a2d98e..09b35444 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.js
+++ b/chrome/browser/resources/md_bookmarks/toolbar.js
@@ -44,6 +44,12 @@
     selectedFolder_: String,
 
     /** @private */
+    canSortFolder_: {
+      type: Boolean,
+      computed: 'computeCanSortFolder_(canChangeList_, selectedFolder_)',
+    },
+
+    /** @private */
     canChangeList_: {
       type: Boolean,
       computed:
@@ -84,8 +90,7 @@
 
   /** @private */
   onSortTap_: function() {
-    chrome.bookmarkManagerPrivate.sortChildren(
-        assert(this.getState().selectedFolder));
+    chrome.bookmarkManagerPrivate.sortChildren(assert(this.selectedFolder_));
     bookmarks.ToastManager.getInstance().show(
         loadTimeData.getString('toastFolderSorted'), true);
     this.closeDropdownMenu_();
@@ -95,7 +100,7 @@
   onAddBookmarkTap_: function() {
     var dialog =
         /** @type {BookmarksEditDialogElement} */ (this.$.addDialog.get());
-    dialog.showAddDialog(false, assert(this.getState().selectedFolder));
+    dialog.showAddDialog(false, assert(this.selectedFolder_));
     this.closeDropdownMenu_();
   },
 
@@ -103,7 +108,7 @@
   onAddFolderTap_: function() {
     var dialog =
         /** @type {BookmarksEditDialogElement} */ (this.$.addDialog.get());
-    dialog.showAddDialog(true, assert(this.getState().selectedFolder));
+    dialog.showAddDialog(true, assert(this.selectedFolder_));
     this.closeDropdownMenu_();
   },
 
@@ -121,7 +126,7 @@
 
   /** @private */
   onDeleteSelectionTap_: function() {
-    var selection = this.getState().selection.items;
+    var selection = this.selectedItems_;
     var commandManager = bookmarks.CommandManager.getInstance();
     assert(commandManager.canExecute(Command.DELETE, selection));
     commandManager.handle(Command.DELETE, selection);
@@ -162,6 +167,15 @@
    * @return {boolean}
    * @private
    */
+  computeCanSortFolder_: function() {
+    return this.canChangeList_ &&
+        this.getState().nodes[this.selectedFolder_].children.length > 0;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
   computeCanChangeList_: function() {
     return !this.searchTerm_ &&
         bookmarks.util.canReorderChildren(
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.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index d7d2123a..10c310d6 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -198,7 +198,9 @@
         <div class="settings-box single-column stretch">
           <network-property-list
               fields="[[getInfoFields_(networkProperties)]]"
-              property-dict="[[networkProperties]]">
+              edit-field-types="[[getInfoEditFieldTypes_(networkProperties)]]"
+              property-dict="[[networkProperties]]"
+              on-property-change="onNetworkPropertyChange_">
           </network-property-list>
         </div>
       </template>
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..8be3b0c1 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,
@@ -674,6 +674,9 @@
       CrOnc.setTypeProperty(onc, 'APN', value);
     } else if (field == 'SIMLockStatus') {
       CrOnc.setTypeProperty(onc, 'SIMLockStatus', value);
+    } else if (field == 'VPN.Host') {
+      // TODO(stevenjb): Generalize this section if we add more editable fields.
+      CrOnc.setProperty(onc, field, value);
     } else {
       console.error('Unexpected property change event: ' + field);
       return;
@@ -888,6 +891,21 @@
   },
 
   /**
+   * @return {!Object} A dictionary of editable fields in the info section.
+   * @private
+   */
+  getInfoEditFieldTypes_: function() {
+    /** @dict */ var editFields = {};
+    var type = this.networkProperties.Type;
+    if (type == CrOnc.Type.VPN && !!this.networkProperties.VPN) {
+      var vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
+      if (vpnType != 'ThirdPartyVPN')
+        editFields['VPN.Host'] = 'String';
+    }
+    return editFields;
+  },
+
+  /**
    * @return {!Array<string>} The fields to display in the Advanced section.
    * @private
    */
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index 36a244a3..4e7bb799 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -3,7 +3,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="../settings_shared_css.html">
 
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..fa248dd 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);
   },
 
   /**
@@ -181,8 +185,10 @@
    *           key: (string|undefined)}} e
    */
   onInputMethodTap_: function(e) {
-    // Taps on the paper-icon-button are handled in onInputMethodOptionsTap_.
-    if (e.target.tagName == 'PAPER-ICON-BUTTON')
+    // Taps on the button are handled in onInputMethodOptionsTap_.
+    // TODO(dschuyler): The row has two operations that are not clearly
+    // delineated. crbug.com/740691
+    if (e.target.tagName == 'BUTTON')
       return;
 
     // Ignore key presses other than <Enter>.
@@ -421,7 +427,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..12dd0624 100644
--- a/chrome/browser/resources/settings/people_page/change_picture.html
+++ b/chrome/browser/resources/settings/people_page/change_picture.html
@@ -1,17 +1,15 @@
 <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/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/chromeos/change_picture/cr_picture_list.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/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys/iron-a11y-keys.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="../i18n_setup.html">
-<link rel="import" href="change_picture_browser_proxy.html">
 <link rel="import" href="../route.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="change_picture_browser_proxy.html">
 
 <dom-module id="settings-change-picture">
   <template>
@@ -19,135 +17,50 @@
       #container {
         -webkit-margin-start: 16px;
         align-items: flex-start;
-        outline: none;
         padding-top: 16px;
       }
 
-      #availableIcons {
-        margin: -8px;
-      }
-
-      #availableIcons img,
-      #availableIcons iron-icon {
-        border-radius: 4px;
-        margin: 8px;
-      }
-
-      #availableIcons img {
-        height: 64px;
-        padding: 2px;
-        vertical-align: top;
-        width: 64px;
-      }
-
-      #availableIcons iron-icon {
-        --iron-icon-fill-color: var(--google-grey-500);
-        --iron-icon-height: 32px;
-        --iron-icon-width: 32px;
-        border: 1px solid var(--google-grey-500);
-        padding: 17px;
-      }
-
-      #availableIcons .iron-selected {
-        border: 2px solid var(--google-blue-500);
-      }
-
-      #availableIcons img.iron-selected {
-        padding: 0;
-      }
-
-      #availableIcons iron-icon.iron-selected {
-        padding: 16px;
-      }
-
-      #authorCredit,
-      #authorCredit a {
+      #authorCredit {
         color: var(--paper-grey-600);
+        margin-top: 8px;
       }
 
-      #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"
-          on-keys-pressed="onKeysPress_">
-      </iron-a11y-keys>
-      <div id="availableIcons" class="start">
-        <iron-selector id="selector" on-iron-activate="onImageActivate_"
-            selected-item="{{selectedItem_}}" role="radiogroup">
-          <iron-icon id="cameraImage" role="radio"
-              data-type$="[[selectionTypesEnum_.CAMERA]]"
-              icon="cr:camera-alt" title="$i18n{takePhoto}"
-              hidden="[[!cameraPresent_]]">
-          </iron-icon>
-          <iron-icon data-type$="[[selectionTypesEnum_.FILE]]" role="radio"
-              icon="cr:folder" title="$i18n{chooseFile}">
-          </iron-icon>
-          <img id="profileImage" role="radio"
-              data-type$="[[selectionTypesEnum_.PROFILE]]"
-              src="[[profileImageUrl_]]" title="$i18n{profilePhotoLoading}">
-          <img id="oldImage" data-type$="[[selectionTypesEnum_.OLD]]"
-              role="radio" src="[[oldImageUrl_]]" hidden="[[!oldImageUrl_]]"
-              title="$i18n{oldPhoto}">
-          <template is="dom-repeat" items="[[defaultImages_]]">
-            <img data-type$="[[selectionTypesEnum_.DEFAULT]]" role="radio"
-                data-default-image-index$="[[index]]" src="[[item.url]]"
-                title="[[item.title]]">
-          </template>
-        </iron-selector>
-        <template is="dom-if" if="[[isAuthorCreditShown_(selectedItem_)]]">
-          <div id="authorCredit">
-            $i18n{authorCredit}
-            [[getAuthorName_(selectedItem_, defaultImages_)]]
-            <a href="[[getAuthorWebsite_(selectedItem_, defaultImages_)]]"
-                target="_blank">
-              [[getAuthorWebsite_(selectedItem_, defaultImages_)]]
-            </a>
-          </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}"
+    <div id="container" class="settings-box">
+      <div class="start">
+        <cr-picture-list id="pictureList"
+            camera-present="[[cameraPresent_]]"
+            default-images="[[defaultImages_]]"
+            selected-item="{{selectedItem_}}"
+            choose-file-label="$i18n{chooseFile}"
+            old-image-label="$i18n{oldPhoto}"
+            profile-image-label="$i18n{profilePhoto}"
+            profile-image-loading-label="$i18n{profilePhotoLoading}"
             take-photo-label="$i18n{takePhoto}">
-        </cr-camera>
+        </cr-picture-list>
+        <div id="authorCredit"
+            hidden="[[!isAuthorCreditShown_(selectedItem_)]]">
+          [[getAuthorCredit_(selectedItem_, defaultImages_)]]
+          <a href="[[getAuthorWebsite_(selectedItem_, defaultImages_)]]"
+              target="_blank">
+            [[getAuthorWebsite_(selectedItem_, defaultImages_)]]
+          </a>
+        </div>
       </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..26902bdf 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,29 +30,11 @@
      * 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,
-
-    /**
-     * The url of the Old image, which is the existing image sourced from
-     * the camera, a file, or a deprecated default image. It defaults to an
-     * empty string instead of undefined, because Polymer bindings don't behave
-     * as expected with undefined properties.
-     * @private {string}
-     */
-    oldImageUrl_: {
-      type: String,
-      value: '',
-    },
-
-    /**
-     * The url of the profile image.
-     * @private {string}
-     */
-    profileImageUrl_: {
-      type: String,
-      value: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING',
+    selectedItem_: {
+      type: Object,
+      value: null,
     },
 
     /**
@@ -89,35 +47,26 @@
         return [];
       },
     },
+  },
 
-    /** @private */
-    selectionTypesEnum_: {
-      type: Object,
-      value: ChangePictureSelectionTypes,
-      readOnly: true,
-    },
+  listeners: {
+    'discard-image': 'onDiscardImage_',
+    'image-activate': 'onImageActivate_',
+    '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}
-   */
-  fallbackImage_: null,
-
-  /**
-   * Type of the last selected icon. This is used to jump back to the camera
-   * after the user discards a newly taken photo.
-   * @private {string}
-   */
-  lastSelectedImageType_: '',
+  /** @private {?CrPictureListElement} */
+  pictureList_: null,
 
   /** @override */
   ready: function() {
     this.browserProxy_ = settings.ChangePictureBrowserProxyImpl.getInstance();
+    this.pictureList_ =
+        /** @type {CrPictureListElement} */ (this.$.pictureList);
   },
 
   /** @override */
@@ -137,16 +86,9 @@
 
   /** @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
-      // when navigating away. The selector element doesn't fire its upward
-      // data binding unless its selected item has changed.
-      this.selectedItem_ = this.$.selector.selectedItem;
-      // Focus the container by default so that the arrow keys work (and since
-      // we use the focus highlight to show which picture is selected).
-      this.$.container.focus();
+      this.pictureList_.setFocus();
     } else {
       // Ensure we deactivate the camera when we navigate away.
       this.selectedItem_ = null;
@@ -169,19 +111,7 @@
    * @private
    */
   receiveSelectedImage_: function(imageUrl) {
-    var index = this.$.selector.items.findIndex(function(image) {
-      return image.dataset.type == ChangePictureSelectionTypes.DEFAULT &&
-          image.src == imageUrl;
-    });
-    assert(index != -1, 'Default image not found: ' + imageUrl);
-
-    this.fallbackImage_ = this.$.selector.items[index];
-
-    // If user is currently taking a photo, do not steal the focus.
-    if (!this.selectedItem_ ||
-        this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) {
-      this.$.selector.select(index);
-    }
+    this.pictureList_.setSelectedImageUrl(imageUrl);
   },
 
   /**
@@ -193,8 +123,7 @@
    * @private
    */
   receiveOldImage_: function(imageUrl) {
-    this.oldImageUrl_ = imageUrl;
-    this.$.selector.select(this.$.selector.indexOf(this.$.oldImage));
+    this.pictureList_.setOldImageUrl(imageUrl);
   },
 
   /**
@@ -204,19 +133,7 @@
    * @private
    */
   receiveProfileImage_: function(imageUrl, selected) {
-    this.profileImageUrl_ = imageUrl;
-    this.$.profileImage.title = this.i18n('profilePhoto');
-
-    if (!selected)
-      return;
-
-    this.fallbackImage_ = this.$.profileImage;
-
-    // If user is currently taking a photo, do not steal the focus.
-    if (!this.selectedItem_ ||
-        this.selectedItem_.dataset.type != ChangePictureSelectionTypes.CAMERA) {
-      this.$.selector.select(this.$.selector.indexOf(this.$.profileImage));
-    }
+    this.pictureList_.setProfileImageUrl(imageUrl, selected);
   },
 
   /**
@@ -230,24 +147,24 @@
 
   /**
    * Selects an image element.
-   * @param {!ChangePictureImageElement} image
+   * @param {!CrPicture.ImageElement} image
    * @private
    */
   selectImage_: function(image) {
     switch (image.dataset.type) {
-      case ChangePictureSelectionTypes.CAMERA:
-        // Nothing needs to be done.
+      case CrPicture.SelectionTypes.CAMERA:
+        /** CrPicturePreviewElement */ (this.$.picturePreview).takePhoto();
         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:
@@ -256,84 +173,12 @@
   },
 
   /**
-   * Handler for when accessibility-specific keys are pressed.
-   * @param {!{detail: !{key: string, keyboardEvent: Object}}} e
-   */
-  onKeysPress_: function(e) {
-    if (!this.selectedItem_)
-      return;
-
-    // In the old Options user images grid, the 'up' and 'down' keys had
-    // different behavior depending on whether ChromeVox was on or off.
-    // If ChromeVox was on, 'up' or 'down' would select the next or previous
-    // image on the left or right. If ChromeVox was off, it would select the
-    // image spatially above or below using calculated columns.
-    //
-    // The code below implements the simple behavior of selecting the image
-    // to the left or right (as if ChromeVox was always on).
-    //
-    // TODO(tommycli): Investigate if it's necessary to calculate columns
-    // and select the image on the top or bottom for non-ChromeVox users.
-    var /** IronSelectorElement */ selector = this.$.selector;
-    switch (e.detail.key) {
-      case 'up':
-      case 'left':
-        // This loop always terminates because the file and profile icons are
-        // never hidden.
-        do {
-          selector.selectPrevious();
-        } while (this.selectedItem_.hidden);
-
-        if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE)
-          this.selectImage_(this.selectedItem_);
-
-        this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
-        e.detail.keyboardEvent.preventDefault();
-        break;
-
-      case 'down':
-      case 'right':
-        // This loop always terminates because the file and profile icons are
-        // never hidden.
-        do {
-          selector.selectNext();
-        } while (this.selectedItem_.hidden);
-
-        if (this.selectedItem_.dataset.type != ChangePictureSelectionTypes.FILE)
-          this.selectImage_(this.selectedItem_);
-
-        this.lastSelectedImageType_ = this.selectedItem_.dataset.type;
-        e.detail.keyboardEvent.preventDefault();
-        break;
-
-      case 'enter':
-      case 'space':
-        if (this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.CAMERA) {
-          var /** CrCameraElement */ camera = this.$.camera;
-          camera.takePhoto();
-        } else if (
-            this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.FILE) {
-          this.browserProxy_.chooseFile();
-        } else if (
-            this.selectedItem_.dataset.type ==
-            ChangePictureSelectionTypes.OLD) {
-          this.onTapDiscardOldImage_();
-        }
-        break;
-    }
-  },
-
-  /**
-   * Handler for when the an image is activated.
-   * @param {!Event} event
+   * Handler for when an image is activated.
+   * @param {!{detail: !CrPicture.ImageElement}} event
    * @private
    */
   onImageActivate_: function(event) {
-    var image = event.detail.item;
-    this.lastSelectedImageType_ = image.dataset.type;
-    this.selectImage_(image);
+    this.selectImage_(event.detail);
   },
 
   /**
@@ -342,7 +187,7 @@
    */
   onPhotoTaken_: function(event) {
     this.browserProxy_.photoTaken(event.detail.photoDataUrl);
-    this.$.container.focus();
+    this.pictureList_.setFocus();
     announceAccessibleMessage(
         loadTimeData.getString('photoCaptureAccessibleText'));
   },
@@ -359,20 +204,12 @@
   },
 
   /**
-   * 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() {
-    this.oldImageUrl_ = '';
-
-    if (this.lastSelectedImageType_ == ChangePictureSelectionTypes.CAMERA)
-      this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage));
-
-    if (this.fallbackImage_ != null) {
-      this.selectImage_(this.fallbackImage_);
-      return;
-    }
+  onDiscardImage_: function() {
+    this.pictureList_.setOldImageUrl('');
 
     // If the user has not chosen an image since opening the subpage and
     // discards the current photo, select the first default image.
@@ -383,92 +220,61 @@
   },
 
   /**
-   * @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.
    * @private
    */
-  getAuthorName_: function(selectedItem, defaultImages) {
-    if (!this.isAuthorCreditShown_(selectedItem))
+  getAuthorCredit_: function(selectedItem, defaultImages) {
+    var index = selectedItem ? selectedItem.dataset.index : undefined;
+    if (index === undefined)
       return '';
-
-    assert(
-        selectedItem.dataset.defaultImageIndex !== null &&
-        selectedItem.dataset.defaultImageIndex < defaultImages.length);
-    return defaultImages[selectedItem.dataset.defaultImageIndex].author;
+    assert(index < defaultImages.length);
+    return this.i18n('authorCreditText', defaultImages[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.
+   * @return {string} The author name for the selected default image. An empty
+   *     string is returned if there is no valid author name.
    * @private
    */
   getAuthorWebsite_: function(selectedItem, defaultImages) {
-    if (!this.isAuthorCreditShown_(selectedItem))
+    var index = selectedItem ? selectedItem.dataset.index : undefined;
+    if (index === undefined)
       return '';
-
-    assert(
-        selectedItem.dataset.defaultImageIndex !== null &&
-        selectedItem.dataset.defaultImageIndex < defaultImages.length);
-    return defaultImages[selectedItem.dataset.defaultImageIndex].website;
+    assert(index < defaultImages.length);
+    return defaultImages[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..e6609691 100644
--- a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -6,7 +6,9 @@
     {
       '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_list',
+        '<(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_engine_entry.html b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
index 72ec9a26..1b3bea51 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
@@ -39,11 +39,6 @@
       #url-column {
         flex: 4;
       }
-
-      :host(:not([show-dots_])) paper-icon-button {
-        pointer-events: none;
-        visibility: hidden;
-      }
     </style>
 
     <template is="dom-if" if="[[showEditSearchEngineDialog_]]" restamp>
@@ -58,7 +53,7 @@
       </div>
       <div id="keyword-column"><div>[[engine.keyword]]</div></div>
       <div id="url-column" class="text-elide">[[engine.url]]</div>
-      <button is="paper-icon-button-light" class="icon-more-vert" 
+      <button is="paper-icon-button-light" class="icon-more-vert"
           on-tap="onDotsTap_" title="$i18n{moreActions}" focus-row-control
           focus-type="cr-menu-button">
       </button>
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.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index bcf5d788..e05030c 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -37,7 +37,6 @@
         margin-bottom: 10px;
       }
     </style>
-    <content select="paper-icon-button"></content>
     <div id="noSearchResults" hidden$="[[!showNoResultsFound_]]">
       <div>$i18n{searchNoResults}</div>
       <div>$i18nRaw{searchNoResultsHelp}</div>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index db5ed45..571e8076 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_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index 97b8820..12d8169 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -19,10 +19,6 @@
         padding-bottom: 60px;
       }
 
-      :host-context([dir=rtl]) paper-icon-button[icon='settings:arrow-back'] {
-        transform: scaleX(-1);  /* Flip on the X axis (aka mirror). */
-      }
-
       #headerLine {
         min-height: 40px;
         padding-bottom: 12px;
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/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html
index 4bd940c..9de80593 100644
--- a/chrome/browser/resources/settings/settings_vars_css.html
+++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -89,14 +89,6 @@
     --iron-icon-width: var(--cr-icon-size);
     --paper-checkbox-label-color: inherit;
 
-    --paper-icon-button: {
-      /**
-       * This makes the icons 20px (in combination with --cr-icon-ripple-size),
-       * since paper-icon-button>iron-icon width and height are hard-coded to
-       * 100%.
-       */
-      padding: var(--cr-icon-ripple-padding);
-    };
     --paper-input-container-focus-color: var(--google-blue-500);
     --paper-input-container-input: {
       color: inherit;
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/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
new file mode 100644
index 0000000..bfd44a3e
--- /dev/null
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -0,0 +1,351 @@
+// 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 <map>
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/signin/account_tracker_service_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/common/profile_management_switches.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/embedded_test_server/request_handler_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using net::test_server::BasicHttpResponse;
+using net::test_server::HttpRequest;
+using net::test_server::HttpResponse;
+
+namespace {
+
+enum SignoutType {
+  kSignoutTypeFirst = 0,
+
+  kAllAccounts = 0,       // Sign out from all accounts.
+  kMainAccount = 1,       // Sign out from main account only.
+  kSecondaryAccount = 2,  // Sign out from secondary account only.
+
+  kSignoutTypeLast
+};
+
+const char kAuthorizationCode[] = "authorization_code";
+const char kDiceResponseHeader[] = "X-Chrome-ID-Consistency-Response";
+const char kGoogleSignoutResponseHeader[] = "Google-Accounts-SignOut";
+const char kMainEmail[] = "main_email@example.com";
+const char kMainGaiaID[] = "main_gaia_id";
+const char kOAuth2TokenExchangeURL[] = "/oauth2/v4/token";
+const char kSecondaryEmail[] = "secondary_email@example.com";
+const char kSecondaryGaiaID[] = "secondary_gaia_id";
+const char kSigninURL[] = "/signin";
+const char kSignoutURL[] = "/signout";
+const char kSignedOutMessage[] = "signed_out";
+
+}  // namespace
+
+namespace FakeGaia {
+
+// Handler for the signin page on the embedded test server.
+// The response has the content of the Dice request header in its body, and has
+// the Dice response header.
+std::unique_ptr<HttpResponse> HandleSigninURL(const HttpRequest& request) {
+  if (!net::test_server::ShouldHandle(request, kSigninURL))
+    return nullptr;
+
+  std::string header_value = "None";
+  auto it = request.headers.find(signin::kDiceRequestHeader);
+  if (it != request.headers.end())
+    header_value = it->second;
+
+  std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+  http_response->set_content(header_value);
+  http_response->set_content_type("text/plain");
+  http_response->AddCustomHeader(
+      kDiceResponseHeader,
+      base::StringPrintf(
+          "action=SIGNIN,authuser=1,id=%s,email=%s,authorization_code=%s",
+          kMainGaiaID, kMainEmail, kAuthorizationCode));
+  http_response->AddCustomHeader("Cache-Control", "no-store");
+  return std::move(http_response);
+}
+
+// Handler for the signout page on the embedded test server.
+// Responds with a Google-Accounts-SignOut header for the main account, the
+// secondary account, or both (depending on the SignoutType, which is encoded in
+// the query string).
+std::unique_ptr<HttpResponse> HandleSignoutURL(const HttpRequest& request) {
+  if (!net::test_server::ShouldHandle(request, kSignoutURL))
+    return nullptr;
+
+  // Build signout header.
+  int query_value;
+  EXPECT_TRUE(base::StringToInt(request.GetURL().query(), &query_value));
+  SignoutType signout_type = static_cast<SignoutType>(query_value);
+  EXPECT_GE(signout_type, kSignoutTypeFirst);
+  EXPECT_LT(signout_type, kSignoutTypeLast);
+  std::string signout_header_value;
+  if (signout_type == kAllAccounts || signout_type == kMainAccount) {
+    signout_header_value =
+        base::StringPrintf("email=\"%s\", obfuscatedid=\"%s\", sessionindex=1",
+                           kMainEmail, kMainGaiaID);
+  }
+  if (signout_type == kAllAccounts || signout_type == kSecondaryAccount) {
+    if (!signout_header_value.empty())
+      signout_header_value += ", ";
+    signout_header_value +=
+        base::StringPrintf("email=\"%s\", obfuscatedid=\"%s\", sessionindex=2",
+                           kSecondaryEmail, kSecondaryGaiaID);
+  }
+
+  std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+  http_response->set_content(kSignedOutMessage);
+  http_response->set_content_type("text/plain");
+  http_response->AddCustomHeader(kGoogleSignoutResponseHeader,
+                                 signout_header_value);
+  http_response->AddCustomHeader("Cache-Control", "no-store");
+  return std::move(http_response);
+}
+
+// Handler for OAuth2 token exchange.
+// Checks that the request is well formatted and returns a refresh token in a
+// JSON dictionary.
+std::unique_ptr<HttpResponse> HandleOAuth2TokenExchangeURL(
+    bool* out_token_requested,
+    const HttpRequest& request) {
+  if (!net::test_server::ShouldHandle(request, kOAuth2TokenExchangeURL))
+    return nullptr;
+
+  // Check that the authorization code is somewhere in the request body.
+  if (!request.has_content)
+    return nullptr;
+  if (request.content.find(kAuthorizationCode) == std::string::npos)
+    return nullptr;
+
+  // The token must be exchanged only once.
+  EXPECT_FALSE(*out_token_requested);
+
+  *out_token_requested = true;
+
+  std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+  std::string content =
+      "{"
+      "  \"access_token\":\"access_token\","
+      "  \"refresh_token\":\"refresh_token\","
+      "  \"expires_in\":9999"
+      "}";
+
+  http_response->set_content(content);
+  http_response->set_content_type("text/plain");
+  http_response->AddCustomHeader("Cache-Control", "no-store");
+  return std::move(http_response);
+}
+
+}  // namespace FakeGaia
+
+class DiceBrowserTest : public InProcessBrowserTest,
+                        public OAuth2TokenService::Observer {
+ protected:
+  ~DiceBrowserTest() override {}
+
+  DiceBrowserTest()
+      : https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
+        token_requested_(false),
+        refresh_token_available_(false) {
+    https_server_.RegisterDefaultHandler(
+        base::Bind(&FakeGaia::HandleSigninURL));
+    https_server_.RegisterDefaultHandler(
+        base::Bind(&FakeGaia::HandleSignoutURL));
+    https_server_.RegisterDefaultHandler(
+        base::Bind(&FakeGaia::HandleOAuth2TokenExchangeURL, &token_requested_));
+  }
+
+  // Navigates to the given path on the test server.
+  void NavigateToURL(const std::string& path) {
+    ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(path));
+  }
+
+  // Returns the token service.
+  ProfileOAuth2TokenService* GetTokenService() {
+    return ProfileOAuth2TokenServiceFactory::GetForProfile(
+        browser()->profile());
+  }
+
+  AccountTrackerService* GetAccountTrackerService() {
+    return AccountTrackerServiceFactory::GetForProfile(browser()->profile());
+  }
+
+  // Returns the account ID associated with kMainEmail, kMainGaiaID.
+  std::string GetMainAccountID() {
+    return GetAccountTrackerService()->PickAccountIdForAccount(kMainGaiaID,
+                                                               kMainEmail);
+  }
+
+  // Returns the account ID associated with kSecondaryEmail, kSecondaryGaiaID.
+  std::string GetSecondaryAccountID() {
+    return GetAccountTrackerService()->PickAccountIdForAccount(kSecondaryGaiaID,
+                                                               kSecondaryEmail);
+  }
+
+  // Signin with a main account and add token for a secondary account.
+  void SetupSignedInAccounts() {
+    // Signin main account.
+    SigninManager* signin_manager =
+        SigninManagerFactory::GetForProfile(browser()->profile());
+    signin_manager->StartSignInWithRefreshToken(
+        "refresh_token", kMainGaiaID, kMainEmail, "password",
+        SigninManager::OAuthTokenFetchedCallback());
+    ASSERT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+    ASSERT_EQ(GetMainAccountID(), signin_manager->GetAuthenticatedAccountId());
+
+    // Add a token for a secondary account.
+    std::string secondary_account_id =
+        GetAccountTrackerService()->SeedAccountInfo(kSecondaryEmail,
+                                                    kSecondaryGaiaID);
+    GetTokenService()->UpdateCredentials(kSecondaryEmail, "other_token");
+    ASSERT_TRUE(
+        GetTokenService()->RefreshTokenIsAvailable(secondary_account_id));
+  }
+
+  // Navigate to a Gaia URL setting the Google-Accounts-SignOut header.
+  void SignOutWithDice(SignoutType signout_type) {
+    NavigateToURL(base::StringPrintf("%s?%i", kSignoutURL, signout_type));
+    std::string page_content;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        "window.domAutomationController.send(document.body.textContent);",
+        &page_content));
+    EXPECT_EQ(kSignedOutMessage, page_content);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // InProcessBrowserTest:
+  void SetUp() override {
+    ASSERT_TRUE(https_server_.InitializeAndListen());
+    InProcessBrowserTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    const GURL& base_url = https_server_.base_url();
+    command_line->AppendSwitchASCII(switches::kGaiaUrl, base_url.spec());
+    command_line->AppendSwitchASCII(switches::kGoogleApisUrl, base_url.spec());
+    switches::EnableAccountConsistencyDiceForTesting(command_line);
+  }
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    https_server_.StartAcceptingConnections();
+    GetTokenService()->AddObserver(this);
+  }
+
+  void TearDownOnMainThread() override {
+    GetTokenService()->RemoveObserver(this);
+  }
+
+  // OAuth2TokenService::Observer:
+  void OnRefreshTokenAvailable(const std::string& account_id) override {
+    if (account_id == GetMainAccountID())
+      refresh_token_available_ = true;
+  }
+
+  net::EmbeddedTestServer https_server_;
+  bool token_requested_;
+  bool refresh_token_available_;
+};
+
+// Checks that signin on Gaia triggers the fetch for a refresh token.
+IN_PROC_BROWSER_TEST_F(DiceBrowserTest, Signin) {
+  // Navigate to Gaia and sign in.
+  NavigateToURL(kSigninURL);
+
+  // Check that the Dice request header was sent.
+  std::string header_value;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "window.domAutomationController.send(document.body.textContent);",
+      &header_value));
+  EXPECT_EQ(base::StringPrintf(
+                "client_id=%s",
+                GaiaUrls::GetInstance()->oauth2_chrome_client_id().c_str()),
+            header_value);
+
+  // Check that the token was requested and added to the token service.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(token_requested_);
+  EXPECT_TRUE(refresh_token_available_);
+  EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+}
+
+// Checks that the Dice signout flow works and deletes all tokens.
+IN_PROC_BROWSER_TEST_F(DiceBrowserTest, SignoutMainAccount) {
+  // Start from a signed-in state.
+  SetupSignedInAccounts();
+
+  // Signout from main account.
+  SignOutWithDice(kMainAccount);
+
+  // Check that the user is signed out and all tokens are deleted.
+  SigninManager* signin_manager =
+      SigninManagerFactory::GetForProfile(browser()->profile());
+  EXPECT_TRUE(signin_manager->GetAuthenticatedAccountId().empty());
+  EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+  EXPECT_FALSE(
+      GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID()));
+}
+
+// Checks that signing out from a secondary account does not delete the main
+// token.
+IN_PROC_BROWSER_TEST_F(DiceBrowserTest, SignoutSecondaryAccount) {
+  // Start from a signed-in state.
+  SetupSignedInAccounts();
+
+  // Signout from secondary account.
+  SignOutWithDice(kSecondaryAccount);
+
+  // Check that the user is still signed in from main account, but secondary
+  // token is deleted.
+  SigninManager* signin_manager =
+      SigninManagerFactory::GetForProfile(browser()->profile());
+  EXPECT_EQ(GetMainAccountID(), signin_manager->GetAuthenticatedAccountId());
+  EXPECT_TRUE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+  EXPECT_FALSE(
+      GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID()));
+}
+
+// Checks that the Dice signout flow works and deletes all tokens.
+IN_PROC_BROWSER_TEST_F(DiceBrowserTest, SignoutAllAccounts) {
+  // Start from a signed-in state.
+  SetupSignedInAccounts();
+
+  // Signout from all accounts.
+  SignOutWithDice(kAllAccounts);
+
+  // Check that the user is signed out and all tokens are deleted.
+  SigninManager* signin_manager =
+      SigninManagerFactory::GetForProfile(browser()->profile());
+  EXPECT_TRUE(signin_manager->GetAuthenticatedAccountId().empty());
+  EXPECT_FALSE(GetTokenService()->RefreshTokenIsAvailable(GetMainAccountID()));
+  EXPECT_FALSE(
+      GetTokenService()->RefreshTokenIsAvailable(GetSecondaryAccountID()));
+}
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/translate/translate_service_unittest.cc b/chrome/browser/translate/translate_service_unittest.cc
index 455a7d7..46a52cd 100644
--- a/chrome/browser/translate/translate_service_unittest.cc
+++ b/chrome/browser/translate/translate_service_unittest.cc
@@ -5,6 +5,9 @@
 #include "chrome/browser/translate/translate_service.h"
 
 #include "build/build_config.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/translate/core/browser/translate_download_manager.h"
 #include "content/public/common/url_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -14,6 +17,7 @@
 #include "extensions/common/constants.h"
 #endif
 
+// Test the check that determines if a URL should be translated.
 TEST(TranslateServiceTest, CheckTranslatableURL) {
   GURL empty_url = GURL(std::string());
   EXPECT_FALSE(TranslateService::IsTranslatableURL(empty_url));
@@ -41,3 +45,40 @@
   GURL right_url = GURL("http://www.tamurayukari.com/");
   EXPECT_TRUE(TranslateService::IsTranslatableURL(right_url));
 }
+
+// Test selection of translation target language.
+TEST(TranslateServiceTest, GetTargetLanguage) {
+  TranslateService::InitializeForTesting();
+
+  translate::TranslateDownloadManager* const download_manager =
+      translate::TranslateDownloadManager::GetInstance();
+  download_manager->ResetForTesting();
+
+#if defined(OS_CHROMEOS)
+  const char kLanguagePrefName[] = "settings.language.preferred_languages";
+#else
+  const char kLanguagePrefName[] = "intl.accept_languages";
+#endif
+  // Setup the accept / preferred languages preferences.
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterStringPref(kLanguagePrefName, std::string());
+  prefs.SetString(kLanguagePrefName, "fr");
+
+  // Test valid application locale.
+  download_manager->set_application_locale("en");
+  EXPECT_EQ("en", TranslateService::GetTargetLanguage(&prefs));
+
+  download_manager->set_application_locale("es");
+  EXPECT_EQ("es", TranslateService::GetTargetLanguage(&prefs));
+
+  // No valid application locale, so fall back to accept language.
+  download_manager->set_application_locale("");
+  EXPECT_EQ("fr", TranslateService::GetTargetLanguage(&prefs));
+
+  // Ensure unsupported language is ignored.
+  prefs.SetString(kLanguagePrefName, "xx,fr");
+  EXPECT_EQ("fr", TranslateService::GetTargetLanguage(&prefs));
+
+  download_manager->ResetForTesting();
+  TranslateService::ShutdownForTesting();
+}
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..af9d1a5 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 {
@@ -601,8 +580,9 @@
   }
 }
 
-keyboard::KeyboardUI* ChromeShellDelegate::CreateKeyboardUI() {
-  return new ChromeKeyboardUI(ProfileManager::GetActiveUserProfile());
+std::unique_ptr<keyboard::KeyboardUI> ChromeShellDelegate::CreateKeyboardUI() {
+  return base::MakeUnique<ChromeKeyboardUI>(
+      ProfileManager::GetActiveUserProfile());
 }
 
 ash::AccessibilityDelegate* ChromeShellDelegate::CreateAccessibilityDelegate() {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 1c56d93..4cae06d 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -40,7 +40,7 @@
   void PreInit() override;
   void PreShutdown() override;
   void Exit() override;
-  keyboard::KeyboardUI* CreateKeyboardUI() override;
+  std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   void ShelfInit() override;
   void ShelfShutdown() override;
diff --git a/chrome/browser/ui/ash/keyboard_controller_browsertest.cc b/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
index 2f529dd3..f141d8b 100644
--- a/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
@@ -239,7 +239,7 @@
   auto* controller = keyboard::KeyboardController::GetInstance();
 
   EXPECT_EQ(controller->GetStateForTest(),
-            keyboard::KeyboardControllerState::INITIAL);
+            keyboard::KeyboardControllerState::LOADING_EXTENSION);
   // Call ShowKeyboard twice. The second call should has no effect.
   controller->ShowKeyboard(false);
   EXPECT_EQ(controller->GetStateForTest(),
@@ -253,6 +253,16 @@
             keyboard::KeyboardControllerState::SHOWN);
 }
 
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardStateTest, StateResolvesAfterPreload) {
+  auto* controller = keyboard::KeyboardController::GetInstance();
+
+  EXPECT_EQ(controller->GetStateForTest(),
+            keyboard::KeyboardControllerState::LOADING_EXTENSION);
+  WaitControllerStateChangesTo(keyboard::KeyboardControllerState::HIDDEN);
+  EXPECT_EQ(controller->GetStateForTest(),
+            keyboard::KeyboardControllerState::HIDDEN);
+}
+
 IN_PROC_BROWSER_TEST_F(VirtualKeyboardStateTest, OpenAndCloseAndOpen) {
   auto* controller = keyboard::KeyboardController::GetInstance();
 
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/passwords/password_manager_presenter.cc b/chrome/browser/ui/passwords/password_manager_presenter.cc
index 0ce28242..fd883523 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter.cc
@@ -379,7 +379,7 @@
   PasswordStore* store = page_->GetPasswordStore();
   if (store != NULL) {
     cancelable_task_tracker()->TryCancelAll();
-    store->GetAutofillableLoginsWithAffiliatedRealms(this);
+    store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(this);
   } else {
     LOG(ERROR) << "No password store! Cannot display passwords.";
   }
@@ -403,7 +403,7 @@
   PasswordStore* store = page_->GetPasswordStore();
   if (store != NULL) {
     cancelable_task_tracker()->TryCancelAll();
-    store->GetBlacklistLoginsWithAffiliatedRealms(this);
+    store->GetBlacklistLoginsWithAffiliationAndBrandingInformation(this);
   } else {
     LOG(ERROR) << "No password store! Cannot display exceptions.";
   }
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_file_dialog.cc b/chrome/browser/ui/webui/media_router/media_router_file_dialog.cc
index 3489362..b9012aa 100644
--- a/chrome/browser/ui/webui/media_router/media_router_file_dialog.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_file_dialog.cc
@@ -8,6 +8,8 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/media/router/media_router_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/media_router/issue.h"
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..5b55691f 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_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index d43ee64..08ea3dd 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1369,7 +1369,7 @@
     {"oldPhoto", IDS_SETTINGS_CHANGE_PICTURE_OLD_PHOTO},
     {"profilePhotoLoading", IDS_SETTINGS_CHANGE_PICTURE_PROFILE_LOADING_PHOTO},
     {"previewAltText", IDS_SETTINGS_CHANGE_PICTURE_PREVIEW_ALT},
-    {"authorCredit", IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_TEXT},
+    {"authorCreditText", IDS_SETTINGS_CHANGE_PICTURE_AUTHOR_CREDIT_TEXT},
     {"photoFlippedAccessibleText", IDS_SETTINGS_PHOTO_FLIP_ACCESSIBLE_TEXT},
     {"photoFlippedBackAccessibleText",
      IDS_SETTINGS_PHOTO_FLIPBACK_ACCESSIBLE_TEXT},
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/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 76e85e60..699b69a 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -76,6 +76,8 @@
 const char kWallpaperManagerId[] = "obklkkbkpaoaejdabbfldmcfplpdgolj";
 const char kWebstoreWidgetAppId[] = "fbjakikfhfdajcamjleinfciajelkpek";
 const char kZIPUnpackerExtensionId[] = "oedeeodfidgoollimchfdnbmhcpnklnd";
+const char kZipArchiverExtensionId[] = "dmboannefpncccogfdikhmhpmdnddgoe";
+const char kZipArchiverExtensionPath[] = "chromeos/zip_archiver";
 #else
 // The extension id for the web store extension.
 const char kChromeVoxExtensionId[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 049567f..bf4ca1cb 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -224,6 +224,10 @@
 extern const char kWebstoreWidgetAppId[];
 // The extension id of the new ZIP unpacker extension.
 extern const char kZIPUnpackerExtensionId[];
+// The extension id of the zip archiver extension.
+extern const char kZipArchiverExtensionId[];
+// Path to preinstalled zip archiver extension.
+extern const char kZipArchiverExtensionPath[];
 #endif
 
 // What causes an extension to be installed? Used in histograms, so don't
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/BUILD.gn b/chrome/installer/zucchini/BUILD.gn
index f417400..ba3b0b5 100644
--- a/chrome/installer/zucchini/BUILD.gn
+++ b/chrome/installer/zucchini/BUILD.gn
@@ -8,6 +8,8 @@
 static_library("zucchini_lib") {
   sources = [
     "buffer_view.h",
+    "crc32.cc",
+    "crc32.h",
     "disassembler.cc",
     "disassembler.h",
     "image_utils.h",
@@ -41,6 +43,7 @@
 test("zucchini_unittests") {
   sources = [
     "buffer_view_unittest.cc",
+    "crc32_unittest.cc",
     "typed_value_unittest.cc",
   ]
 
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/installer/zucchini/crc32.cc b/chrome/installer/zucchini/crc32.cc
new file mode 100644
index 0000000..c406355
--- /dev/null
+++ b/chrome/installer/zucchini/crc32.cc
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/crc32.h"
+
+#include <array>
+
+#include "base/logging.h"
+
+namespace zucchini {
+
+namespace {
+
+std::array<uint32_t, 256> MakeCrc32Table() {
+  constexpr uint32_t kCrc32Poly = 0xEDB88320;
+
+  std::array<uint32_t, 256> crc32Table;
+  for (uint32_t i = 0; i < 256; ++i) {
+    uint32_t r = i;
+    for (int j = 0; j < 8; ++j)
+      r = (r >> 1) ^ (kCrc32Poly & ~((r & 1) - 1));
+    crc32Table[i] = r;
+  }
+  return crc32Table;
+}
+
+}  // namespace
+
+// Minimalistic CRC-32 implementation for Zucchini usage. Adapted from LZMA SDK
+// (found at third_party/lzma_sdk/7zCrc.c), which is public domain.
+uint32_t CalculateCrc32(const uint8_t* first, const uint8_t* last) {
+  DCHECK_GE(last, first);
+
+  static const std::array<uint32_t, 256> kCrc32Table = MakeCrc32Table();
+
+  uint32_t ret = 0xFFFFFFFF;
+  for (; first != last; ++first)
+    ret = kCrc32Table[(ret ^ *first) & 0xFF] ^ (ret >> 8);
+  return ret ^ 0xFFFFFFFF;
+}
+
+}  // namespace zucchini
diff --git a/chrome/installer/zucchini/crc32.h b/chrome/installer/zucchini/crc32.h
new file mode 100644
index 0000000..8b3558eb
--- /dev/null
+++ b/chrome/installer/zucchini/crc32.h
@@ -0,0 +1,17 @@
+// 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_INSTALLER_ZUCCHINI_CRC32_H_
+#define CHROME_INSTALLER_ZUCCHINI_CRC32_H_
+
+#include <cstdint>
+
+namespace zucchini {
+
+// Calculates CRC-32 of the given range [|first|, |last|).
+uint32_t CalculateCrc32(const uint8_t* first, const uint8_t* last);
+
+}  // namespace zucchini
+
+#endif  // CHROME_INSTALLER_ZUCCHINI_CRC32_H_
diff --git a/chrome/installer/zucchini/crc32_unittest.cc b/chrome/installer/zucchini/crc32_unittest.cc
new file mode 100644
index 0000000..d9768a6
--- /dev/null
+++ b/chrome/installer/zucchini/crc32_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/crc32.h"
+
+#include <cstdint>
+#include <iterator>
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+constexpr uint8_t bytes[] = {0x10, 0x32, 0x54, 0x76, 0x98,
+                             0xBA, 0xDC, 0xFE, 0x10, 0x00};
+
+TEST(Crc32Test, All) {
+  // Results can be verified with any CRC-32 calculator found online.
+
+  // Empty region.
+  EXPECT_EQ(0x00000000U, CalculateCrc32(std::begin(bytes), std::begin(bytes)));
+
+  // Single byte.
+  EXPECT_EQ(0xCFB5FFE9U,
+            CalculateCrc32(std::begin(bytes), std::begin(bytes) + 1));
+
+  // Same byte (0x10) appearing at different location.
+  EXPECT_EQ(0xCFB5FFE9U,
+            CalculateCrc32(std::begin(bytes) + 8, std::begin(bytes) + 9));
+
+  // Single byte of 0.
+  EXPECT_EQ(0xD202EF8DU,
+            CalculateCrc32(std::begin(bytes) + 9, std::end(bytes)));
+
+  // Whole region.
+  EXPECT_EQ(0xA86FD7D6U, CalculateCrc32(std::begin(bytes), std::end(bytes)));
+
+  // Whole region excluding 0 at end.
+  EXPECT_EQ(0x0762F38BU,
+            CalculateCrc32(std::begin(bytes), std::begin(bytes) + 9));
+
+  EXPECT_DCHECK_DEATH(CalculateCrc32(std::begin(bytes) + 1, std::begin(bytes)));
+}
+
+}  // namespace zucchini
diff --git a/chrome/renderer/extensions/app_hooks_delegate.cc b/chrome/renderer/extensions/app_hooks_delegate.cc
index d66ccded..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/extensions/chrome_extensions_renderer_client.cc b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
index 4d4241e..e33e827 100644
--- a/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
+++ b/chrome/renderer/extensions/chrome_extensions_renderer_client.cc
@@ -136,6 +136,16 @@
   return extension_dispatcher_.get();
 }
 
+void ChromeExtensionsRendererClient::OnExtensionLoaded(
+    const extensions::Extension& extension) {
+  resource_request_policy_->OnExtensionLoaded(extension);
+}
+
+void ChromeExtensionsRendererClient::OnExtensionUnloaded(
+    const extensions::ExtensionId& extension_id) {
+  resource_request_policy_->OnExtensionUnloaded(extension_id);
+}
+
 void ChromeExtensionsRendererClient::RenderThreadStarted() {
   content::RenderThread* thread = content::RenderThread::Get();
   extension_dispatcher_delegate_.reset(
diff --git a/chrome/renderer/extensions/chrome_extensions_renderer_client.h b/chrome/renderer/extensions/chrome_extensions_renderer_client.h
index 6bd77c5f..2f8f5e5a 100644
--- a/chrome/renderer/extensions/chrome_extensions_renderer_client.h
+++ b/chrome/renderer/extensions/chrome_extensions_renderer_client.h
@@ -47,6 +47,9 @@
   bool IsIncognitoProcess() const override;
   int GetLowestIsolatedWorldId() const override;
   extensions::Dispatcher* GetDispatcher() override;
+  void OnExtensionLoaded(const extensions::Extension& extension) override;
+  void OnExtensionUnloaded(
+      const extensions::ExtensionId& extension_id) override;
 
   // See ChromeContentRendererClient methods with the same names.
   void RenderThreadStarted();
diff --git a/chrome/renderer/extensions/resource_request_policy.cc b/chrome/renderer/extensions/resource_request_policy.cc
index 0519a63..681d86c9 100644
--- a/chrome/renderer/extensions/resource_request_policy.cc
+++ b/chrome/renderer/extensions/resource_request_policy.cc
@@ -30,6 +30,30 @@
 
 ResourceRequestPolicy::ResourceRequestPolicy(Dispatcher* dispatcher)
     : dispatcher_(dispatcher) {}
+ResourceRequestPolicy::~ResourceRequestPolicy() = default;
+
+void ResourceRequestPolicy::OnExtensionLoaded(const Extension& extension) {
+  if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) ||
+      // Extensions below manifest version 2 had all resources accessible by
+      // default.
+      // TODO(devlin): Two things - first, we might not have any v1 extensions
+      // anymore; second, this should maybe be included in
+      // HasWebAccessibleResources().
+      extension.manifest_version() < 2 ||
+      WebviewInfo::HasWebviewAccessibleResources(
+          extension, dispatcher_->webview_partition_id()) ||
+      // Hosted app icons are accessible.
+      // TODO(devlin): Should we incorporate this into
+      // WebAccessibleResourcesInfo?
+      (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty())) {
+    web_accessible_ids_.insert(extension.id());
+  }
+}
+
+void ResourceRequestPolicy::OnExtensionUnloaded(
+    const ExtensionId& extension_id) {
+  web_accessible_ids_.erase(extension_id);
+}
 
 // This method does a security check whether chrome-extension:// URLs can be
 // requested by the renderer. Since this is in an untrusted process, the browser
@@ -42,14 +66,70 @@
     ui::PageTransition transition_type) {
   CHECK(resource_url.SchemeIs(kExtensionScheme));
 
-  const Extension* extension =
-      RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url);
-  if (!extension) {
-    // Allow the load in the case of a non-existent extension. We'll just get a
-    // 404 from the browser process.
+  GURL frame_url = frame->GetDocument().Url();
+
+  // The page_origin may be GURL("null") for unique origins like data URLs,
+  // but this is ok for the checks below.  We only care if it matches the
+  // current extension or has a devtools scheme.
+  GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL();
+
+  GURL extension_origin = resource_url.GetOrigin();
+
+  // We always allow loads in the following cases, regardless of web accessible
+  // resources:
+
+  // Empty urls (needed for some edge cases when we have empty urls).
+  if (frame_url.is_empty())
+    return true;
+
+  // Extensions requesting their own resources (frame_url check is for images,
+  // page_url check is for iframes).
+  // TODO(devlin): We should be checking the ancestor chain, not just the
+  // top-level frame. Additionally, we should be checking the security origin
+  // of the frame, to account for about:blank subframes being scripted by an
+  // extension parent (though we'll still need the frame origin check for
+  // sandboxed frames).
+  if (frame_url.GetOrigin() == extension_origin ||
+      page_origin == extension_origin) {
     return true;
   }
 
+  if (!ui::PageTransitionIsWebTriggerable(transition_type))
+    return true;
+
+  // Unreachable web page error page (to allow showing the icon of the
+  // unreachable app on this page).
+  if (frame_url == content::kUnreachableWebDataURL)
+    return true;
+
+  bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme);
+  // Note: we check |web_accessible_ids_| (rather than first looking up the
+  // extension in the registry and checking that) to be more resistant against
+  // timing attacks. This way, determining access for an extension that isn't
+  // installed takes the same amount of time as determining access for an
+  // extension with no web accessible resources. We aren't worried about any
+  // extensions with web accessible resources, since those are inherently
+  // identifiable.
+  if (!is_dev_tools && !web_accessible_ids_.count(extension_origin.host()))
+    return false;
+
+  const Extension* extension =
+      RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url);
+  if (is_dev_tools) {
+    // Allow the load in the case of a non-existent extension. We'll just get a
+    // 404 from the browser process.
+    // TODO(devlin): Can this happen? Does devtools potentially make requests
+    // to non-existent extensions?
+    if (!extension)
+      return true;
+    // Devtools (chrome-extension:// URLs are loaded into frames of devtools to
+    // support the devtools extension APIs).
+    if (!chrome_manifest_urls::GetDevToolsPage(extension).is_empty())
+      return true;
+  }
+
+  DCHECK(extension);
+
   // Disallow loading of packaged resources for hosted apps. We don't allow
   // hybrid hosted/packaged apps. The one exception is access to icons, since
   // some extensions want to be able to do things like create their own
@@ -72,43 +152,15 @@
       !WebviewInfo::IsResourceWebviewAccessible(
           extension, dispatcher_->webview_partition_id(),
           resource_url.path())) {
-    GURL frame_url = frame->GetDocument().Url();
-
-    // The page_origin may be GURL("null") for unique origins like data URLs,
-    // but this is ok for the checks below.  We only care if it matches the
-    // current extension or has a devtools scheme.
-    GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL();
-
-    // Exceptions are:
-    // - empty origin (needed for some edge cases when we have empty origins)
-    bool is_empty_origin = frame_url.is_empty();
-    // - extensions requesting their own resources (frame_url check is for
-    //     images, page_url check is for iframes)
-    bool is_own_resource = frame_url.GetOrigin() == extension->url() ||
-                           page_origin == extension->url();
-    // - devtools (chrome-extension:// URLs are loaded into frames of devtools
-    //     to support the devtools extension APIs)
-    bool is_dev_tools =
-        page_origin.SchemeIs(content::kChromeDevToolsScheme) &&
-        !chrome_manifest_urls::GetDevToolsPage(extension).is_empty();
-    bool transition_allowed =
-        !ui::PageTransitionIsWebTriggerable(transition_type);
-    // - unreachable web page error page (to allow showing the icon of the
-    //   unreachable app on this page)
-    bool is_error_page = frame_url == content::kUnreachableWebDataURL;
-
-    if (!is_empty_origin && !is_own_resource &&
-        !is_dev_tools && !transition_allowed && !is_error_page) {
-      std::string message = base::StringPrintf(
-          "Denying load of %s. Resources must be listed in the "
-          "web_accessible_resources manifest key in order to be loaded by "
-          "pages outside the extension.",
-          resource_url.spec().c_str());
-      frame->AddMessageToConsole(
-          blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
-                                   blink::WebString::FromUTF8(message)));
-      return false;
-    }
+    std::string message = base::StringPrintf(
+        "Denying load of %s. Resources must be listed in the "
+        "web_accessible_resources manifest key in order to be loaded by "
+        "pages outside the extension.",
+        resource_url.spec().c_str());
+    frame->AddMessageToConsole(
+        blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError,
+                                 blink::WebString::FromUTF8(message)));
+    return false;
   }
 
   return true;
diff --git a/chrome/renderer/extensions/resource_request_policy.h b/chrome/renderer/extensions/resource_request_policy.h
index 1c2f4fd..c487a6a 100644
--- a/chrome/renderer/extensions/resource_request_policy.h
+++ b/chrome/renderer/extensions/resource_request_policy.h
@@ -5,7 +5,10 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_RESOURCE_REQUEST_POLICY_H_
 #define CHROME_RENDERER_EXTENSIONS_RESOURCE_REQUEST_POLICY_H_
 
+#include <set>
+
 #include "base/macros.h"
+#include "extensions/common/extension_id.h"
 #include "ui/base/page_transition_types.h"
 
 class GURL;
@@ -15,13 +18,17 @@
 }
 
 namespace extensions {
-
 class Dispatcher;
+class Extension;
 
 // Encapsulates the policy for when chrome-extension:// URLs can be requested.
 class ResourceRequestPolicy {
  public:
   explicit ResourceRequestPolicy(Dispatcher* dispatcher);
+  ~ResourceRequestPolicy();
+
+  void OnExtensionLoaded(const Extension& extension);
+  void OnExtensionUnloaded(const ExtensionId& extension);
 
   // Returns true if the chrome-extension:// |resource_url| can be requested
   // from |frame_url|. In some cases this decision is made based upon how
@@ -34,6 +41,10 @@
  private:
   Dispatcher* dispatcher_;
 
+  // The set of extension IDs with any potentially web- or webview-accessible
+  // resources.
+  std::set<ExtensionId> web_accessible_ids_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceRequestPolicy);
 };
 
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..624127d5 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/",
@@ -1739,6 +1738,9 @@
       sources +=
           [ "../browser/ssl/captive_portal_blocking_page_browsertest.cc" ]
     }
+    if (enable_dice_support) {
+      sources += [ "../browser/signin/dice_browsertest.cc" ]
+    }
     if (!enable_one_click_signin) {
       sources -= [ "../browser/ui/sync/one_click_signin_links_delegate_impl_browsertest.cc" ]
     }
@@ -3153,7 +3155,6 @@
     "../browser/metrics/chrome_browser_main_extra_parts_metrics_unittest.cc",
     "../browser/metrics/chrome_metrics_service_accessor_unittest.cc",
     "../browser/metrics/perf/perf_provider_chromeos_unittest.cc",
-    "../browser/metrics/process_memory_metrics_emitter_unittest.cc",
     "../browser/metrics/subprocess_metrics_provider_unittest.cc",
     "../browser/metrics/thread_watcher_android_unittest.cc",
     "../browser/metrics/thread_watcher_unittest.cc",
@@ -3206,8 +3207,6 @@
     "../browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/page_load_metrics_util_unittest.cc",
-    "../browser/page_load_metrics/test/ukm_tester.cc",
-    "../browser/page_load_metrics/test/ukm_tester.h",
     "../browser/page_load_metrics/user_input_tracker_unittest.cc",
     "../browser/password_manager/chrome_password_manager_client_unittest.cc",
     "../browser/password_manager/password_manager_internals_service_unittest.cc",
@@ -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/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
index 6770ad8..698f061 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/FakeSuggestionsSource.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.test.util.browser.suggestions;
 
+import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.createDummySuggestions;
+
 import android.graphics.Bitmap;
 
 import org.chromium.base.Callback;
@@ -67,6 +69,31 @@
     }
 
     /**
+     * Creates and sets the suggestions to be returned for a given category.
+     * @return The suggestions created.
+     * @see ContentSuggestionsTestUtils#createDummySuggestions(int, int)
+     * @see #setSuggestionsForCategory(int, List)
+     */
+    public List<SnippetArticle> createAndSetSuggestions(int count, @CategoryInt int category) {
+        List<SnippetArticle> suggestions = createDummySuggestions(count, category);
+        setSuggestionsForCategory(category, suggestions);
+        return suggestions;
+    }
+
+    /**
+     * Creates and sets the suggestions to be returned for a given category.
+     * @return The suggestions created.
+     * @see ContentSuggestionsTestUtils#createDummySuggestions(int, int, String)
+     * @see #setSuggestionsForCategory(int, List)
+     */
+    public List<SnippetArticle> createAndSetSuggestions(
+            int count, @CategoryInt int category, String suffix) {
+        List<SnippetArticle> suggestions = createDummySuggestions(count, category, suffix);
+        setSuggestionsForCategory(category, suggestions);
+        return suggestions;
+    }
+
+    /**
      * Sets the metadata to be returned for a given category.
      */
     public void setInfoForCategory(@CategoryInt int category, SuggestionsCategoryInfo info) {
@@ -193,9 +220,8 @@
     }
 
     @Override
-    public void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds) {
-        throw new UnsupportedOperationException();
-    }
+    public void fetchSuggestions(@CategoryInt int category, String[] displayedSuggestionIds,
+            Callback<List<SnippetArticle>> callback) {}
 
     @Override
     public void fetchContextualSuggestions(String url, Callback<List<SnippetArticle>> callback) {
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/webrtc/peerconnection_rtp.js b/chrome/test/data/webrtc/peerconnection_rtp.js
index 638ae8a..f2fafae 100644
--- a/chrome/test/data/webrtc/peerconnection_rtp.js
+++ b/chrome/test/data/webrtc/peerconnection_rtp.js
@@ -227,6 +227,14 @@
   returnToTest('ok-receiver-with-track-not-found');
 }
 
+/**
+ * Invokes the GC and returns "ok-gc".
+ */
+function collectGarbage() {
+  gc();
+  returnToTest('ok-gc');
+}
+
 // Internals.
 
 /** @private */
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
index 62e5101..62105e3 100644
--- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -13,6 +13,9 @@
   /** @type {?NodeList<HTMLElement>} */
   var items = null;
 
+  /** @type {HTMLElement} */
+  var dots = null;
+
   setup(function() {
     PolymerTest.clearBody();
 
@@ -28,10 +31,13 @@
 
     menu = document.querySelector('dialog[is=cr-action-menu]');
     items = menu.querySelectorAll('.dropdown-item');
+    dots = document.querySelector('#dots');
     assertEquals(3, items.length);
   });
 
   teardown(function() {
+    document.body.style.direction = 'ltr';
+
     if (menu.open)
       menu.close();
   });
@@ -45,25 +51,25 @@
   }
 
   test('hidden or disabled items', function() {
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
     down();
     assertEquals(menu.root.activeElement, items[0]);
 
     menu.close();
     items[0].hidden = true;
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
     down();
     assertEquals(menu.root.activeElement, items[1]);
 
     menu.close();
     items[1].disabled = true;
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
     down();
     assertEquals(menu.root.activeElement, items[2]);
   });
 
   test('focus after down/up arrow', function() {
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
 
     // The menu should be focused when shown, but not on any of the items.
     assertEquals(menu, document.activeElement);
@@ -93,8 +99,8 @@
     assertEquals(items[0], menu.root.activeElement);
   });
 
-  test('pressing up arrow when no focus will focus last item', function(){
-    menu.showAt(document.querySelector('#dots'));
+  test('pressing up arrow when no focus will focus last item', function() {
+    menu.showAt(dots);
     assertEquals(menu, document.activeElement);
 
     up();
@@ -106,7 +112,7 @@
     var item = document.createElement('button');
     item.classList.add('dropdown-item');
     menu.insertBefore(item, items[0]);
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
 
     down();
     assertEquals(item, menu.root.activeElement);
@@ -122,7 +128,7 @@
   });
 
   test('close on resize', function() {
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
     assertTrue(menu.open);
 
     window.dispatchEvent(new CustomEvent('resize'));
@@ -130,7 +136,7 @@
   });
 
   test('close on popstate', function() {
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
     assertTrue(menu.open);
 
     window.dispatchEvent(new CustomEvent('popstate'));
@@ -140,7 +146,6 @@
   /** @param {string} key The key to use for closing. */
   function testFocusAfterClosing(key) {
     return new Promise(function(resolve) {
-      var dots = document.querySelector('#dots');
       menu.showAt(dots);
       assertTrue(menu.open);
 
@@ -151,7 +156,9 @@
     });
   }
 
-  test('close on Tab', function() { return testFocusAfterClosing('Tab'); });
+  test('close on Tab', function() {
+    return testFocusAfterClosing('Tab');
+  });
   test('close on Escape', function() {
     return testFocusAfterClosing('Escape');
   });
@@ -162,7 +169,7 @@
       node.dispatchEvent(e);
     }
 
-    menu.showAt(document.querySelector('#dots'));
+    menu.showAt(dots);
 
     // Moving mouse on option 1 should focus it.
     assertNotEquals(items[0], menu.root.activeElement);
@@ -174,6 +181,12 @@
     assertNotEquals(items[0], menu.root.activeElement);
     assertEquals(menu, document.activeElement);
 
+    // Moving mouse on a disabled item should focus the menu.
+    items[2].setAttribute('disabled', '');
+    makeMouseoverEvent(items[2]);
+    assertNotEquals(items[2], menu.root.activeElement);
+    assertEquals(menu, document.activeElement);
+
     // Mouse movements should override keyboard focus.
     down();
     down();
@@ -259,7 +272,7 @@
       height: 0,
       maxX: menuWidth * 2 - 10,
     });
-    assertEquals(`${menuWidth  - 10}px`, menu.style.left);
+    assertEquals(`${menuWidth - 10}px`, menu.style.left);
     assertEquals(`0px`, menu.style.top);
     menu.close();
 
@@ -270,88 +283,122 @@
     assertEquals(140 - menuWidth, menu.offsetLeft);
     assertEquals('250px', menu.style.top);
     menu.close();
-    document.body.style.direction = 'ltr';
   });
 
-  test('offscreen scroll positioning', function() {
+  suite('offscreen scroll positioning', function() {
     var bodyHeight = 10000;
     var bodyWidth = 20000;
     var containerLeft = 5000;
     var containerTop = 10000;
     var containerWidth = 500;
     var containerHeight = 500;
-    document.body.innerHTML = `
-      <style>
-        body {
-          height: ${bodyHeight}px;
-          width: ${bodyWidth}px;
-        }
+    var menuWidth = 100;
+    var menuHeight = 200;
 
-        #container {
-          overflow: auto;
-          position: absolute;
-          top: ${containerTop}px;
-          left: ${containerLeft}px;
-          height: ${containerHeight}px;
-          width: ${containerWidth}px;
-        }
+    setup(function() {
+      document.body.scrollTop = 0;
+      document.body.scrollLeft = 0;
+      document.body.innerHTML = `
+        <style>
+          body {
+            height: ${bodyHeight}px;
+            width: ${bodyWidth}px;
+          }
 
-        #inner-container {
-          height: 1000px;
-          width: 1000px;
-        }
-      </style>
-      <div id="container">
-        <div id="inner-container">
-          <button id="dots">...</button>
-          <dialog is="cr-action-menu">
-            <button class="dropdown-item">Un</button>
-            <hr>
-            <button class="dropdown-item">Dos</button>
-            <button class="dropdown-item">Tres</button>
-          </dialog>
+          #container {
+            overflow: auto;
+            position: absolute;
+            top: ${containerTop}px;
+            left: ${containerLeft}px;
+            right: ${containerLeft}px;
+            height: ${containerHeight}px;
+            width: ${containerWidth}px;
+          }
+
+          #inner-container {
+            height: 1000px;
+            width: 1000px;
+          }
+
+          dialog {
+            height: ${menuHeight};
+            width: ${menuWidth};
+            padding: 0;
+          }
+        </style>
+        <div id="container">
+          <div id="inner-container">
+            <button id="dots">...</button>
+            <dialog is="cr-action-menu">
+              <button class="dropdown-item">Un</button>
+              <hr>
+              <button class="dropdown-item">Dos</button>
+              <button class="dropdown-item">Tres</button>
+            </dialog>
+          </div>
         </div>
-      </div>
-    `;
-    menu = document.querySelector('dialog[is=cr-action-menu]');
-    var dots = document.querySelector('#dots');
+      `;
+      menu = document.querySelector('dialog[is=cr-action-menu]');
+      dots = document.querySelector('#dots');
+    })
 
     // Show the menu, scrolling the body to the button.
-    menu.showAt(
-        dots,
-        {anchorAlignmentX: AnchorAlignment.AFTER_START});
-    assertEquals(`${containerLeft}px`, menu.style.left);
-    assertEquals(`${containerTop}px`, menu.style.top);
-    menu.close();
+    test('simple offscreen', function() {
+      menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+      assertEquals(`${containerLeft}px`, menu.style.left);
+      assertEquals(`${containerTop}px`, menu.style.top);
+      menu.close();
+    });
 
     // Show the menu, scrolling the container to the button, and the body to the
     // button.
-    document.body.scrollLeft = bodyWidth;
-    document.body.scrollTop = bodyHeight;
+    test('offscreen and out of scroll container viewport', function() {
+      document.body.scrollLeft = bodyWidth;
+      document.body.scrollTop = bodyHeight;
+      var container = document.querySelector('#container');
 
-    document.querySelector('#container').scrollLeft = containerLeft;
-    document.querySelector('#container').scrollTop = containerTop;
+      container.scrollLeft = containerLeft;
+      container.scrollTop = containerTop;
 
-    menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
-    assertEquals(`${containerLeft}px`, menu.style.left);
-    assertEquals(`${containerTop}px`, menu.style.top);
-    menu.close();
+      menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+      assertEquals(`${containerLeft}px`, menu.style.left);
+      assertEquals(`${containerTop}px`, menu.style.top);
+      menu.close();
+    });
 
     // Show the menu for an already onscreen button. The anchor should be
     // overridden so that no scrolling happens.
-    document.body.scrollLeft = 0;
-    document.body.scrollTop = 0;
+    test('onscreen forces anchor change', function() {
+      var rect = dots.getBoundingClientRect();
+      document.body.scrollLeft = rect.right - document.body.clientWidth + 10;
+      document.body.scrollTop = rect.bottom - document.body.clientHeight + 10;
 
-    var rect = dots.getBoundingClientRect();
-    document.body.scrollLeft = rect.right - document.body.clientWidth;
-    document.body.scrollTop = rect.bottom - document.body.clientHeight;
+      menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+      var buttonWidth = dots.offsetWidth;
+      var buttonHeight = dots.offsetHeight;
+      assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft);
+      assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop);
+      menu.close();
+    });
 
-    menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
-    var menuWidth = menu.offsetWidth;
-    var menuHeight = menu.offsetHeight;
-    var buttonWidth = dots.offsetWidth;
-    var buttonHeight = dots.offsetHeight;
-    assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft);
-    assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop);
+    test('scroll position maintained for showAtPosition', function() {
+      document.body.scrollLeft = 500;
+      document.body.scrollTop = 1000;
+      menu.showAtPosition({top: 50, left: 50});
+      assertEquals(550, menu.offsetLeft);
+      assertEquals(1050, menu.offsetTop);
+      menu.close();
+    });
+
+    test('rtl', function() {
+      // Anchor to an item in RTL.
+      document.body.style.direction = 'rtl';
+      menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
+      assertEquals(
+          container.offsetLeft + containerWidth - menuWidth,
+          menu.offsetLeft);
+      assertEquals(containerTop, menu.offsetTop);
+      menu.close();
+    });
   });
 });
diff --git a/chrome/test/data/webui/md_bookmarks/toolbar_test.js b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
index f01fcf6d..9fa23a0 100644
--- a/chrome/test/data/webui/md_bookmarks/toolbar_test.js
+++ b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
@@ -19,6 +19,12 @@
             createItem('2'),
             createItem('3'),
             createFolder('4', [], {unmodifiable: 'managed'}),
+            createFolder('5', []),
+            createFolder(
+                '6',
+                [
+                  createItem('61'),
+                ]),
           ])),
       selection: {
         items: new Set(),
@@ -108,4 +114,18 @@
     assertTrue(toolbar.$$('#addBookmarkButton').disabled);
     assertTrue(toolbar.$$('#importBookmarkButton').disabled);
   });
+
+  test('sort button is disabled when folder is empty', function() {
+    MockInteractions.tap(toolbar.$.menuButton);
+
+    store.data.selectedFolder = '6';
+    store.notifyObservers();
+    assertTrue(toolbar.canSortFolder_);
+
+    store.data.selectedFolder = '5';
+    store.notifyObservers();
+
+    assertFalse(toolbar.canSortFolder_);
+    assertTrue(toolbar.$$('#sortButton').disabled);
+  });
 });
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..2035e5d1 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,8 @@
     suite('ChangePictureTests', function() {
       var changePicture = null;
       var browserProxy = null;
-      var crCamera = null;
-      var discardControlBar = null;
+      var crPicturePreview = null;
+      var crPictureList = null;
 
       suiteSetup(function() {
         loadTimeData.overrideValues({
@@ -98,12 +98,13 @@
         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);
+        crPictureList = changePicture.$$('cr-picture-list');
+        assertTrue(!!crPictureList);
+
+        changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
 
         return browserProxy.whenCalled('initialize').then(function() {
           Polymer.dom.flush();
@@ -113,63 +114,81 @@
       teardown(function() { changePicture.remove(); });
 
       test('ChangePictureSelectCamera', function() {
-        var cameraIcon = changePicture.$.cameraImage;
-        assertTrue(!!cameraIcon);
-
         // Force the camera to be absent, even if it's actually present.
         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() {
+          var camera = crPicturePreview.$$('#camera');
+          expectFalse(crPicturePreview.cameraPresent);
+          expectFalse(crPicturePreview.cameraActive_);
+          expectFalse(!!camera && camera.hidden);
 
-        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() {
+          var camera = crPicturePreview.$$('#camera');
+          expectTrue(crPicturePreview.cameraPresent);
+          expectFalse(crPicturePreview.cameraActive_);
+          expectFalse(!!camera && camera.hidden);
 
-        expectFalse(cameraIcon.hidden);
-        expectFalse(crCamera.cameraActive);
+          var cameraImage = crPictureList.$.cameraImage;
+          MockInteractions.tap(cameraImage);
+          Polymer.dom.flush();
+          return new Promise(function(resolve) {
+            changePicture.async(resolve);
+          });
+        }).then(function() {
+          var camera = crPicturePreview.$$('#camera');
+          expectTrue(crPicturePreview.cameraActive_);
+          assertTrue(!!camera && !camera.hidden);
+          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() {
-        var profileImage = changePicture.$.profileImage;
+        var profileImage = crPictureList.$.profileImage;
         assertTrue(!!profileImage);
 
-        expectEquals(undefined, changePicture.selectedItem_);
+        expectEquals(null, changePicture.selectedItem_);
         MockInteractions.tap(profileImage);
 
         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.selectedItem_.dataset.type);
+          changePicture.currentRouteChanged(settings.routes.BASIC);
+          changePicture.currentRouteChanged(settings.routes.CHANGE_PICTURE);
+          expectEquals(null, changePicture.selectedItem_);
         });
       });
 
       test('ChangePictureOldImage', function() {
         // By default there is no old image and the element is hidden.
-        var oldImage = changePicture.$.oldImage;
+        var oldImage = crPictureList.$.oldImage;
         assertTrue(!!oldImage);
         assertTrue(oldImage.hidden);
 
@@ -178,15 +197,17 @@
 
         // 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() {
-        var firstDefaultImage = changePicture.$$('img[data-type="default"]');
+        var firstDefaultImage = crPictureList.$$('img[data-type="default"]');
         assertTrue(!!firstDefaultImage);
 
         MockInteractions.tap(firstDefaultImage);
@@ -196,11 +217,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');
@@ -213,10 +235,8 @@
       });
 
       test('ChangePictureRestoreImageAfterDiscard', function() {
-        var firstDefaultImage = changePicture.$$('img[data-type="default"]');
+        var firstDefaultImage = crPictureList.$$('img[data-type="default"]');
         assertTrue(!!firstDefaultImage);
-        var discardOldImage = changePicture.$.discardOldImage;
-        assertTrue(!!discardOldImage);
 
         MockInteractions.tap(firstDefaultImage);
 
@@ -227,10 +247,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/BUILD.gn b/chromecast/BUILD.gn
index cd88338..af871ae6 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -472,8 +472,11 @@
 buildflag_header("chromecast_features") {
   header = "chromecast_features.h"
   flags = [
+    "ENABLE_ASSISTANT=$enable_assistant",
+    "IS_ANDROID_THINGS=$is_android_things",
     "IS_CAST_AUDIO_ONLY=$is_cast_audio_only",
     "IS_CAST_USING_CMA_BACKEND=$is_cast_using_cma_backend",
+    "SUPPORTS_MULTIZONE=$supports_multizone",
   ]
 }
 
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/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index 850a4f88..974676f 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -149,15 +149,18 @@
     const StringDBusMethodCallback& callback) {
   // Even for stub implementation we have to return different values so that
   // multi-profiles would work.
-  std::string sanitized_username = GetStubSanitizedUsername(cryptohome_id);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, sanitized_username));
+  auto task =
+      service_is_available_
+          ? base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS,
+                           GetStubSanitizedUsername(cryptohome_id))
+          : base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, std::string());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task));
 }
 
 std::string FakeCryptohomeClient::BlockingGetSanitizedUsername(
     const cryptohome::Identification& cryptohome_id) {
-  return GetStubSanitizedUsername(cryptohome_id);
+  return service_is_available_ ? GetStubSanitizedUsername(cryptohome_id)
+                               : std::string();
 }
 
 void FakeCryptohomeClient::AsyncMount(
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/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index 3a7ffa5..cc44dd7 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -64,6 +64,8 @@
   target->SetBoolean("was_parsed_using_autofill_predictions",
                      form.was_parsed_using_autofill_predictions);
   target->SetString("affiliated_web_realm", form.affiliated_web_realm);
+  target->SetString("app_display_name", form.app_display_name);
+  target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
   target->SetBoolean("does_look_like_signup_form",
                      form.does_look_like_signup_form);
   std::ostringstream submission_event_string_stream;
@@ -134,6 +136,8 @@
          is_public_suffix_match == form.is_public_suffix_match &&
          is_affiliation_based_match == form.is_affiliation_based_match &&
          affiliated_web_realm == form.affiliated_web_realm &&
+         app_display_name == form.app_display_name &&
+         app_icon_url == form.app_icon_url &&
          does_look_like_signup_form == form.does_look_like_signup_form &&
          submission_event == form.submission_event;
 }
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h
index 67c0090..825fdabc 100644
--- a/components/autofill/core/common/password_form.h
+++ b/components/autofill/core/common/password_form.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/time/time.h"
@@ -133,11 +134,26 @@
 
   // The web realm affiliated with the Android application, if the form is an
   // Android credential. Otherwise, the string is empty. If there are several
-  // realms affiliated with the application, an arbitrary realm is chosen.
-  // The field is filled out in PasswordStore's InjectAffiliatedWebRealms.
-  // If there was no call of InjectAffiliatedWebRealms, the string is empty.
+  // realms affiliated with the application, an arbitrary realm is chosen. The
+  // field is filled out when the PasswordStore injects affiliation and branding
+  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+  // no prior call to this method, the string is empty.
   std::string affiliated_web_realm;
 
+  // The display name (e.g. Play Store name) of the Android application if the
+  // form is an Android credential. Otherwise, the string is empty. The field is
+  // filled out when the PasswordStore injects affiliation and branding
+  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+  // no prior call to this method, the string is empty.
+  std::string app_display_name;
+
+  // The icon URL (e.g. Play Store icon URL) of the Android application if the
+  // form is an Android credential. Otherwise, the URL is empty. The field is
+  // filled out when the PasswordStore injects affiliation and branding
+  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
+  // no prior call to this method, the URL is empty.
+  GURL app_icon_url;
+
   // The name of the submit button used. Optional; only used in scoring
   // of PasswordForm results from the database to make matches as tight as
   // possible.
diff --git a/components/cast_certificate/cast_cert_validator.cc b/components/cast_certificate/cast_cert_validator.cc
index f10080e6..608f7a7 100644
--- a/components/cast_certificate/cast_cert_validator.cc
+++ b/components/cast_certificate/cast_cert_validator.cc
@@ -13,6 +13,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
+#include "base/stl_util.h"
 #include "components/cast_certificate/cast_crl.h"
 #include "net/cert/internal/cert_issuer_source_static.h"
 #include "net/cert/internal/certificate_policies.h"
@@ -182,8 +183,7 @@
   for (const auto& cert : result_path->path.certs) {
     if (cert->has_policy_oids()) {
       const std::vector<net::der::Input>& policies = cert->policy_oids();
-      if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) !=
-          policies.end()) {
+      if (base::ContainsValue(policies, AudioOnlyPolicyOid())) {
         audio_only = true;
         break;
       }
diff --git a/components/cloud_devices/common/description_items.h b/components/cloud_devices/common/description_items.h
index fa15668..8ceff58 100644
--- a/components/cloud_devices/common/description_items.h
+++ b/components/cloud_devices/common/description_items.h
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/stl_util.h"
 #include "components/cloud_devices/common/cloud_device_description.h"
 
 namespace base {
@@ -63,8 +64,7 @@
   const Option& operator[](size_t i) const { return options_[i]; }
 
   bool Contains(const Option& option) const {
-    return std::find(options_.begin(), options_.end(), option) !=
-           options_.end();
+    return base::ContainsValue(options_, option);
   }
 
   void AddOption(const Option& option) { options_.push_back(option); }
@@ -104,8 +104,7 @@
   const Option& operator[](size_t i) const { return options_[i]; }
 
   bool Contains(const Option& option) const {
-    return std::find(options_.begin(), options_.end(), option) !=
-           options_.end();
+    return base::ContainsValue(options_, option);
   }
 
   const Option& GetDefault() const {
diff --git a/components/component_updater/configurator_impl.cc b/components/component_updater/configurator_impl.cc
index c4b10eb..a595f40 100644
--- a/components/component_updater/configurator_impl.cc
+++ b/components/component_updater/configurator_impl.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/feature_list.h"
+#include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/version.h"
@@ -58,13 +59,6 @@
 const base::Feature kAlternateComponentUrls{"AlternateComponentUrls",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Returns true if and only if |test| is contained in |vec|.
-bool HasSwitchValue(const std::vector<std::string>& vec, const char* test) {
-  if (vec.empty())
-    return 0;
-  return (std::find(vec.begin(), vec.end(), test) != vec.end());
-}
-
 // If there is an element of |vec| of the form |test|=.*, returns the right-
 // hand side of that assignment. Otherwise, returns an empty string.
 // The right-hand side may contain additional '=' characters, allowing for
@@ -101,13 +95,14 @@
   std::vector<std::string> switch_values = base::SplitString(
       cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",",
       base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate);
-  pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings);
-  deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
+  fast_update_ = base::ContainsValue(switch_values, kSwitchFastUpdate);
+  pings_enabled_ = !base::ContainsValue(switch_values, kSwitchDisablePings);
+  deltas_enabled_ =
+      !base::ContainsValue(switch_values, kSwitchDisableDeltaUpdates);
 
 #if defined(OS_WIN)
   background_downloads_enabled_ =
-      !HasSwitchValue(switch_values, kSwitchDisableBackgroundDownloads);
+      !base::ContainsValue(switch_values, kSwitchDisableBackgroundDownloads);
 #else
   background_downloads_enabled_ = false;
 #endif
@@ -119,7 +114,7 @@
     DCHECK(url_source_override_.is_valid());
   }
 
-  if (HasSwitchValue(switch_values, kSwitchRequestParam))
+  if (base::ContainsValue(switch_values, kSwitchRequestParam))
     extra_info_ += "testrequest=\"1\"";
 }
 
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 b53ea782..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/favicon/core/favicon_service_impl.cc b/components/favicon/core/favicon_service_impl.cc
index 4522aad..e267981e 100644
--- a/components/favicon/core/favicon_service_impl.cc
+++ b/components/favicon/core/favicon_service_impl.cc
@@ -44,10 +44,8 @@
   const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
   for (size_t i = 0; i < image_reps.size(); ++i) {
     // Don't save if the scale isn't one of supported favicon scales.
-    if (std::find(favicon_scales.begin(), favicon_scales.end(),
-                  image_reps[i].scale()) == favicon_scales.end()) {
+    if (!base::ContainsValue(favicon_scales, image_reps[i].scale()))
       continue;
-    }
     bitmaps.push_back(image_reps[i].sk_bitmap());
   }
   return bitmaps;
diff --git a/components/guest_view/browser/guest_view_manager_unittest.cc b/components/guest_view/browser/guest_view_manager_unittest.cc
index aeec9016..654efcb 100644
--- a/components/guest_view/browser/guest_view_manager_unittest.cc
+++ b/components/guest_view/browser/guest_view_manager_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "components/guest_view/browser/guest_view_manager_delegate.h"
 #include "components/guest_view/browser/test_guest_view_manager.h"
-#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -29,23 +28,20 @@
 
   std::unique_ptr<WebContents> CreateWebContents() {
     return std::unique_ptr<WebContents>(
-        WebContentsTester::CreateTestWebContents(&browser_context_, NULL));
+        WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
   }
 
  private:
-  content::TestBrowserContext browser_context_;
-
   DISALLOW_COPY_AND_ASSIGN(GuestViewManagerTest);
 };
 
 }  // namespace
 
 TEST_F(GuestViewManagerTest, AddRemove) {
-  content::TestBrowserContext browser_context;
   std::unique_ptr<GuestViewManagerDelegate> delegate(
       new GuestViewManagerDelegate());
   std::unique_ptr<TestGuestViewManager> manager(
-      new TestGuestViewManager(&browser_context, std::move(delegate)));
+      new TestGuestViewManager(browser_context(), std::move(delegate)));
 
   std::unique_ptr<WebContents> web_contents1(CreateWebContents());
   std::unique_ptr<WebContents> web_contents2(CreateWebContents());
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/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 60a142f..6e8b789 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -78,9 +78,9 @@
   callback.Run(*bitmap_result);
 }
 
-void RunWithQueryURLResult(const HistoryService::QueryURLCallback& callback,
+void RunWithQueryURLResult(HistoryService::QueryURLCallback callback,
                            const QueryURLResult* result) {
-  callback.Run(result->success, result->row, result->visits);
+  std::move(callback).Run(result->success, result->row, result->visits);
 }
 
 void RunWithVisibleVisitCountToHostResult(
@@ -670,7 +670,7 @@
 base::CancelableTaskTracker::TaskId HistoryService::QueryURL(
     const GURL& url,
     bool want_visits,
-    const QueryURLCallback& callback,
+    QueryURLCallback callback,
     base::CancelableTaskTracker* tracker) {
   DCHECK(backend_task_runner_) << "History service being called after cleanup";
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -679,8 +679,8 @@
       backend_task_runner_.get(), FROM_HERE,
       base::Bind(&HistoryBackend::QueryURL, history_backend_, url, want_visits,
                  base::Unretained(query_url_result)),
-      base::Bind(&RunWithQueryURLResult, callback,
-                 base::Owned(query_url_result)));
+      base::BindOnce(&RunWithQueryURLResult, std::move(callback),
+                     base::Owned(query_url_result)));
 }
 
 // Statistics ------------------------------------------------------------------
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 425a043..710ac70 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -245,10 +245,11 @@
   // empty.
   //
   // If success is false, neither the row nor the vector will be valid.
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       bool,  // Success flag, when false, nothing else is valid.
       const URLRow&,
-      const VisitVector&)> QueryURLCallback;
+      const VisitVector&)>
+      QueryURLCallback;
 
   // Queries the basic information about the URL in the history database. If
   // the caller is interested in the visits (each time the URL is visited),
@@ -257,7 +258,7 @@
   base::CancelableTaskTracker::TaskId QueryURL(
       const GURL& url,
       bool want_visits,
-      const QueryURLCallback& callback,
+      QueryURLCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Provides the result of a query. See QueryResults in history_types.h.
diff --git a/components/neterror/resources/neterror.css b/components/neterror/resources/neterror.css
index 4649cd82..7ead318 100644
--- a/components/neterror/resources/neterror.css
+++ b/components/neterror/resources/neterror.css
@@ -462,13 +462,6 @@
   }
 }
 
-@media (min-width: 600px) and (max-width: 736px) and (orientation: landscape) {
-  .offline .interstitial-wrapper {
-    margin-left: 0;
-    margin-right: 0;
-  }
-}
-
 @media (min-width: 420px) and (max-width: 736px) and
        (min-height: 240px) and (max-height: 420px) and
        (orientation:landscape) {
@@ -514,3 +507,32 @@
     width: auto;
   }
 }
+
+.arcade-mode,
+.arcade-mode .runner-container,
+.arcade-mode .runner-canvas {
+  max-width: 100%;
+  overflow: hidden;
+}
+
+.arcade-mode #buttons,
+.arcade-mode #main-content {
+  opacity: 0;
+  overflow: hidden;
+}
+
+.arcade-mode .interstitial-wrapper {
+  height: 100vh;
+  max-width: 100%;
+  overflow: hidden;
+}
+
+.arcade-mode .runner-container {
+  left: 0;
+  margin: auto;
+  right: 0;
+  top: 0;
+  transform-origin: top center;
+  transition: transform 250ms cubic-bezier(0.4, 0.0, 1, 1) .4s;
+  z-index: 2;
+}
diff --git a/components/neterror/resources/offline.js b/components/neterror/resources/offline.js
index ed3582f..e89c25d 100644
--- a/components/neterror/resources/offline.js
+++ b/components/neterror/resources/offline.js
@@ -22,7 +22,7 @@
   this.snackbarEl = null;
 
   this.config = opt_config || Runner.config;
-
+  // Logical dimensions of the container.
   this.dimensions = Runner.defaultDimensions;
 
   this.canvas = null;
@@ -96,6 +96,9 @@
 /** @const */
 var IS_TOUCH_ENABLED = 'ontouchstart' in window;
 
+/** @const */
+var ARCADE_MODE_URL = 'chrome://dino/';
+
 /**
  * Default game configuration.
  * @enum {number}
@@ -121,7 +124,8 @@
   MOBILE_SPEED_COEFFICIENT: 1.2,
   RESOURCE_TEMPLATE_ID: 'audio-resources',
   SPEED: 6,
-  SPEED_DROP_COEFFICIENT: 3
+  SPEED_DROP_COEFFICIENT: 3,
+  ARCADE_MODE_TOP_POSITION_PERCENT: 0.1
 };
 
 
@@ -140,6 +144,7 @@
  * @enum {string}
  */
 Runner.classes = {
+  ARCADE_MODE: 'arcade-mode',
   CANVAS: 'runner-canvas',
   CONTAINER: 'runner-container',
   CRASHED: 'crashed',
@@ -225,7 +230,6 @@
   LOAD: 'load'
 };
 
-
 Runner.prototype = {
   /**
    * Whether the easter egg has been disabled. CrOS enterprise enrolled devices.
@@ -418,6 +422,12 @@
         boxStyles.paddingLeft.length - 2));
 
     this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - padding * 2;
+    if (this.isArcadeMode()) {
+      this.dimensions.WIDTH = Math.min(DEFAULT_WIDTH, this.dimensions.WIDTH);
+      if (this.activated) {
+        this.setArcadeModeContainerScale();
+      }
+    }
 
     // Redraw the elements back onto the canvas.
     if (this.canvas) {
@@ -486,6 +496,9 @@
    * Update the game status to started.
    */
   startGame: function() {
+    if (this.isArcadeMode()) {
+      this.setArcadeMode();
+    }
     this.runningTime = 0;
     this.playingIntro = false;
     this.tRex.playingIntro = false;
@@ -826,6 +839,39 @@
   },
 
   /**
+   * Whether the game should go into arcade mode.
+   * @return {boolean}
+   */
+  isArcadeMode: function() {
+    return document.title == ARCADE_MODE_URL;
+  },
+
+  /**
+   * Hides offline messaging for a fullscreen game only experience.
+   */
+  setArcadeMode: function() {
+    document.body.classList.add(Runner.classes.ARCADE_MODE);
+    this.setArcadeModeContainerScale();
+  },
+
+  /**
+   * Sets the scaling for arcade mode.
+   */
+  setArcadeModeContainerScale: function() {
+    var windowHeight = window.innerHeight;
+    var scaleHeight = windowHeight / this.dimensions.HEIGHT;
+    var scaleWidth = window.innerWidth / this.dimensions.WIDTH;
+    var scale = Math.max(1, Math.min(scaleHeight, scaleWidth));
+    var scaledCanvasHeight = this.dimensions.HEIGHT * scale;
+    // Positions the game container at 10% of the available vertical window
+    // height minus the game container height.
+    var translateY = Math.max(0, (windowHeight - scaledCanvasHeight) *
+        Runner.config.ARCADE_MODE_TOP_POSITION_PERCENT);
+    this.containerEl.style.transform = 'scale(' + scale + ') translateY(' +
+        translateY + 'px)';
+  },
+
+  /**
    * Pause the game if the tab is not in focus.
    */
   onVisibilityChange: function(e) {
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/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 0c341ee4..95e8094 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -32,6 +32,9 @@
   <message name="IDS_DANGEROUS_VERBOSE_STATE" desc="Text for the Dangerous Omnibox Verbose State. Displayed when the current page fails the malware check.">
     Dangerous
   </message>
+  <message name="IDS_OFFLINE_VERBOSE_STATE" desc="Text for the Offline Omnibox Verbose state. Displayed when the current page is loaded from a previously-downloaded cache.">
+    Offline
+  </message>
   <if expr="is_ios">
     <message name="IDS_OMNIBOX_EMPTY_HINT" desc="The text displayed in the omnibox when it is empty.">
       Search or type URL
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index 3514f5a..d9567ba 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/barrier_closure.h"
@@ -85,7 +86,7 @@
   }
 }
 
-void AffiliatedMatchHelper::InjectAffiliatedWebRealms(
+void AffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
     std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
     const PasswordFormsCallback& result_callback) {
   std::vector<autofill::PasswordForm*> android_credentials;
@@ -98,30 +99,52 @@
   base::Closure barrier_closure =
       base::BarrierClosure(android_credentials.size(), on_get_all_realms);
   for (auto* form : android_credentials) {
+    // TODO(crbug.com/628988): Rename |GetAffiliations| to
+    // |GetAffiliationsAndBranding|.
     affiliation_service_->GetAffiliations(
         FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
         AffiliationService::StrategyOnCacheMiss::FAIL,
-        base::Bind(&AffiliatedMatchHelper::CompleteInjectAffiliatedWebRealm,
+        base::Bind(&AffiliatedMatchHelper::
+                       CompleteInjectAffiliationAndBrandingInformation,
                    weak_ptr_factory_.GetWeakPtr(), base::Unretained(form),
                    barrier_closure));
   }
 }
 
-void AffiliatedMatchHelper::CompleteInjectAffiliatedWebRealm(
+void AffiliatedMatchHelper::CompleteInjectAffiliationAndBrandingInformation(
     autofill::PasswordForm* form,
     base::Closure barrier_closure,
     const AffiliatedFacets& results,
     bool success) {
-  // If there is a number of realms, choose the first in the list.
-  if (success) {
-    for (const Facet& affiliated_facet : results) {
-      if (affiliated_facet.uri.IsValidWebFacetURI()) {
-        form->affiliated_web_realm =
-            affiliated_facet.uri.canonical_spec() + "/";
-        break;
-      }
-    }
+  if (!success) {
+    barrier_closure.Run();
+    return;
   }
+
+  const FacetURI facet_uri(
+      FacetURI::FromPotentiallyInvalidSpec(form->signon_realm));
+  DCHECK(facet_uri.IsValidAndroidFacetURI());
+
+  // Inject branding information into the form (e.g. the Play Store name and
+  // icon URL). We expect to always find a matching facet URI in the results.
+  auto facet = std::find_if(results.begin(), results.end(),
+                            [&facet_uri](const Facet& affiliated_facet) {
+                              return affiliated_facet.uri == facet_uri;
+                            });
+  DCHECK(facet != results.end());
+  form->app_display_name = facet->branding_info.name;
+  form->app_icon_url = facet->branding_info.icon_url;
+
+  // Inject the affiliated web realm into the form, if available. In case
+  // multiple web realms are available, this will always choose the first
+  // available web realm for injection.
+  auto affiliated_facet = std::find_if(
+      results.begin(), results.end(), [](const Facet& affiliated_facet) {
+        return affiliated_facet.uri.IsValidWebFacetURI();
+      });
+  if (affiliated_facet != results.end())
+    form->affiliated_web_realm = affiliated_facet->uri.canonical_spec() + "/";
+
   barrier_closure.Run();
 }
 
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
index 45f9606..7de6380 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h
@@ -80,12 +80,13 @@
       const PasswordStore::FormDigest& android_form,
       const AffiliatedRealmsCallback& result_callback);
 
-  // Retrieves realms of web sites affiliated with the Android credentials in
-  // |forms|, sets |affiliated_web_realm| of forms, and invokes
-  // |result_callback|.
+  // Retrieves affiliation and branding information about the Android
+  // credentials in |forms|, sets |affiliated_web_realm|, |app_display_name| and
+  // |app_icon_url| of forms, and invokes |result_callback|.
   // NOTE: This will not issue an on-demand network request. If a request to
-  // cache fails, no web realm will be injected into corresponding form.
-  virtual void InjectAffiliatedWebRealms(
+  // cache fails, no affiliation and branding information will be injected into
+  // corresponding form.
+  virtual void InjectAffiliationAndBrandingInformation(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
       const PasswordFormsCallback& result_callback);
 
@@ -127,12 +128,15 @@
       bool success);
 
   // Called back by AffiliationService to supply the list of facets affiliated
-  // with the Android credential in |form|. Sets |form->affiliated_web_realm|,
-  // if |success| is true and |results| is non-empty. Invokes |barrier_closure|.
-  void CompleteInjectAffiliatedWebRealm(autofill::PasswordForm* form,
-                                        base::Closure barrier_closure,
-                                        const AffiliatedFacets& results,
-                                        bool success);
+  // with the Android credential in |form|. Injects affiliation and branding
+  // information by setting |affiliated_web_realm|, |app_display_name| and
+  // |app_icon_url| on |form| if |success| is true and |results| is non-empty.
+  // Invokes |barrier_closure|.
+  void CompleteInjectAffiliationAndBrandingInformation(
+      autofill::PasswordForm* form,
+      base::Closure barrier_closure,
+      const AffiliatedFacets& results,
+      bool success);
 
   // PasswordStore::Observer:
   void OnLoginsChanged(const PasswordStoreChangeList& changes) override;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index 6a369fd2..0ec75d17 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -94,6 +94,8 @@
 const char kTestWebFacetURIAlpha2[] = "https://two.alpha.example.com";
 const char kTestAndroidFacetURIAlpha3[] =
     "android://hash@com.example.alpha.android";
+const char kTestAndroidFacetNameAlpha3[] = "Facet Name Alpha 3";
+const char kTestAndroidFacetIconURLAlpha3[] = "https://example.com/alpha_3.png";
 const char kTestWebRealmAlpha1[] = "https://one.alpha.example.com/";
 const char kTestWebRealmAlpha2[] = "https://two.alpha.example.com/";
 const char kTestAndroidRealmAlpha3[] =
@@ -102,8 +104,12 @@
 const char kTestWebFacetURIBeta1[] = "https://one.beta.example.com";
 const char kTestAndroidFacetURIBeta2[] =
     "android://hash@com.example.beta.android";
+const char kTestAndroidFacetNameBeta2[] = "Facet Name Beta 2";
+const char kTestAndroidFacetIconURLBeta2[] = "https://example.com/beta_2.png";
 const char kTestAndroidFacetURIBeta3[] =
     "android://hash@com.yetanother.beta.android";
+const char kTestAndroidFacetNameBeta3[] = "Facet Name Beta 3";
+const char kTestAndroidFacetIconURLBeta3[] = "https://example.com/beta_3.png";
 const char kTestWebRealmBeta1[] = "https://one.beta.example.com/";
 const char kTestAndroidRealmBeta2[] =
     "android://hash@com.example.beta.android/";
@@ -122,15 +128,21 @@
   return {
       {FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1)},
       {FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha2)},
-      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3)},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
+       FacetBrandingInfo{kTestAndroidFacetNameAlpha3,
+                         GURL(kTestAndroidFacetIconURLAlpha3)}},
   };
 }
 
 AffiliatedFacets GetTestEquivalenceClassBeta() {
   return {
       {FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1)},
-      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2)},
-      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3)},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
+       FacetBrandingInfo{kTestAndroidFacetNameBeta2,
+                         GURL(kTestAndroidFacetIconURLBeta2)}},
+      {FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
+       FacetBrandingInfo{kTestAndroidFacetNameBeta3,
+                         GURL(kTestAndroidFacetIconURLBeta3)}},
   };
 }
 
@@ -272,10 +284,10 @@
   }
 
   std::vector<std::unique_ptr<autofill::PasswordForm>>
-  InjectAffiliatedWebRealms(
+  InjectAffiliationAndBrandingInformation(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
     expecting_result_callback_ = true;
-    match_helper()->InjectAffiliatedWebRealms(
+    match_helper()->InjectAffiliationAndBrandingInformation(
         std::move(forms),
         base::Bind(&AffiliatedMatchHelperTest::OnFormsCallback,
                    base::Unretained(this)));
@@ -437,9 +449,11 @@
               testing::IsEmpty());
 }
 
-// Verifies that InjectAffiliatedWebRealms() injects the realms of web sites
-// affiliated with the given Android application into password forms, if any.
-TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
+// Verifies that InjectAffiliationAndBrandingInformation() injects the realms of
+// web sites affiliated with the given Android application into the password
+// forms, as well as branding information corresponding to the application, if
+// any.
+TEST_F(AffiliatedMatchHelperTest, InjectAffiliationAndBrandingInformation) {
   std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
@@ -455,6 +469,12 @@
       StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
 
   forms.push_back(base::MakeUnique<autofill::PasswordForm>(
+      GetTestAndroidCredentials(kTestAndroidRealmBeta3)));
+  mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
+      FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
+      StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
+
+  forms.push_back(base::MakeUnique<autofill::PasswordForm>(
       GetTestAndroidCredentials(kTestAndroidRealmGamma)));
   mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
       FacetURI::FromCanonicalSpec(kTestAndroidFacetURIGamma),
@@ -470,14 +490,25 @@
 
   size_t expected_form_count = forms.size();
   std::vector<std::unique_ptr<autofill::PasswordForm>> results(
-      InjectAffiliatedWebRealms(std::move(forms)));
+      InjectAffiliationAndBrandingInformation(std::move(forms)));
   ASSERT_EQ(expected_form_count, results.size());
   EXPECT_THAT(results[0]->affiliated_web_realm,
               testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
+  EXPECT_EQ(kTestAndroidFacetNameAlpha3, results[0]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLAlpha3,
+            results[0]->app_icon_url.possibly_invalid_spec());
   EXPECT_THAT(results[1]->affiliated_web_realm,
               testing::Eq(kTestWebRealmBeta1));
-  EXPECT_THAT(results[2]->affiliated_web_realm, testing::IsEmpty());
+  EXPECT_EQ(kTestAndroidFacetNameBeta2, results[1]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLBeta2,
+            results[1]->app_icon_url.possibly_invalid_spec());
+  EXPECT_THAT(results[2]->affiliated_web_realm,
+              testing::Eq(kTestWebRealmBeta1));
+  EXPECT_EQ(kTestAndroidFacetNameBeta3, results[2]->app_display_name);
+  EXPECT_EQ(kTestAndroidFacetIconURLBeta3,
+            results[2]->app_icon_url.possibly_invalid_spec());
   EXPECT_THAT(results[3]->affiliated_web_realm, testing::IsEmpty());
+  EXPECT_THAT(results[4]->affiliated_web_realm, testing::IsEmpty());
 }
 
 // Note: IsValidWebCredential() is tested as part of GetAffiliatedAndroidRealms
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h
index 63498a5..2199744 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_AFFILIATION_FETCHER_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_AFFILIATION_FETCHER_H_
 
+#include <memory>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -78,6 +80,8 @@
 
   // Parses and validates the response protocol buffer message for a list of
   // equivalence classes, stores them into |result| and returns true on success.
+  // It is guaranteed that every one of the requested Facet URIs will be a
+  // member of exactly one returned equivalence class.
   // Returns false if the response was gravely ill-formed or self-inconsistent.
   // Unknown kinds of facet URIs and new protocol buffer fields will be ignored.
   bool ParseResponse(AffiliationFetcherDelegate::Result* result) const;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service.h b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
index 9789c48..2839f45 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service.h
@@ -108,7 +108,9 @@
                   const base::FilePath& db_path);
 
   // Looks up facets affiliated with the facet identified by |facet_uri|, and
-  // invokes |result_callback| with the results.
+  // invokes |result_callback| with the results. It is guaranteed that the
+  // results will contain one facet with URI equal to |facet_uri| when
+  // |result_callback| is invoked with success set to true.
   //
   // If the local cache contains fresh affiliation information for |facet_uri|,
   // the request will be served from cache. Otherwise, |cache_miss_policy|
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
index 16e78e4d..77311bc 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_service_unittest.cc
@@ -112,7 +112,13 @@
   ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
   fake_affiliation_api()->ServeNextRequest();
 
-  mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+  const auto equivalence_class_alpha(GetTestEquivalenceClassAlpha());
+  mock_consumer()->ExpectSuccessWithResult(equivalence_class_alpha);
+  EXPECT_THAT(
+      equivalence_class_alpha,
+      testing::Contains(testing::Field(
+          &Facet::uri, FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1))));
+
   main_task_runner()->RunUntilIdle();
   testing::Mock::VerifyAndClearExpectations(mock_consumer());
 
@@ -124,7 +130,7 @@
   background_task_runner()->RunUntilIdle();
   ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
 
-  mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+  mock_consumer()->ExpectSuccessWithResult(equivalence_class_alpha);
   main_task_runner()->RunUntilIdle();
   testing::Mock::VerifyAndClearExpectations(mock_consumer());
 
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc b/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
index 7d81a7d2..154bd2f4 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <memory>
 
 #include "base/bind.h"
@@ -92,6 +93,10 @@
     expected_facet_uri_ = facet_uri;
   }
 
+  // Returns the facet URI that will be expected to appear in calls coming from
+  // the FacetManager under test.
+  const FacetURI& expected_facet_uri() const { return expected_facet_uri_; }
+
   // Sets up fake |database_content| as the canned response to be returned to
   // the FacetManager every time it calls ReadAffiliationsFromDatabase().
   void set_fake_database_content(
@@ -352,7 +357,13 @@
   }
 
   void ExpectConsumerSuccessCallback() {
-    mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClass());
+    const auto equivalence_class(GetTestEquivalenceClass());
+    mock_consumer()->ExpectSuccessWithResult(equivalence_class);
+    EXPECT_THAT(
+        equivalence_class,
+        testing::Contains(testing::Field(
+            &Facet::uri, fake_facet_manager_host()->expected_facet_uri())));
+
     consumer_task_runner()->RunUntilIdle();
     testing::Mock::VerifyAndClearExpectations(mock_consumer());
   }
diff --git a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
index 8c0fa94dd..22f53ed 100644
--- a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.cc
@@ -4,6 +4,8 @@
 
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
@@ -32,9 +34,11 @@
       .WillOnce(testing::Return(results_to_return));
 }
 
-void MockAffiliatedMatchHelper::ExpectCallToInjectAffiliatedWebRealms(
-    const std::vector<std::string>& results_to_inject) {
-  EXPECT_CALL(*this, OnInjectAffiliatedWebRealmsCalled())
+void MockAffiliatedMatchHelper::
+    ExpectCallToInjectAffiliationAndBrandingInformation(
+        const std::vector<AffiliationAndBrandingInformation>&
+            results_to_inject) {
+  EXPECT_CALL(*this, OnInjectAffiliationAndBrandingInformationCalled())
       .WillOnce(testing::Return(results_to_inject));
 }
 
@@ -54,14 +58,17 @@
   result_callback.Run(affiliated_web_realms);
 }
 
-void MockAffiliatedMatchHelper::InjectAffiliatedWebRealms(
+void MockAffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
     std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
     const PasswordFormsCallback& result_callback) {
-  std::vector<std::string> affiliated_web_realms =
-      OnInjectAffiliatedWebRealmsCalled();
-  DCHECK_EQ(affiliated_web_realms.size(), forms.size());
-  for (size_t i = 0; i < forms.size(); ++i)
-    forms[i]->affiliated_web_realm = affiliated_web_realms[i];
+  const std::vector<AffiliationAndBrandingInformation>& information =
+      OnInjectAffiliationAndBrandingInformationCalled();
+  ASSERT_EQ(information.size(), forms.size());
+  for (size_t i = 0; i < forms.size(); ++i) {
+    forms[i]->affiliated_web_realm = information[i].affiliated_web_realm;
+    forms[i]->app_display_name = information[i].app_display_name;
+    forms[i]->app_icon_url = information[i].app_icon_url;
+  }
   result_callback.Run(std::move(forms));
 }
 
diff --git a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
index 25ee2c02..05095f3 100644
--- a/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
+++ b/components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h
@@ -5,10 +5,15 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_MOCK_AFFILIATED_MATCH_HELPER_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_MOCK_AFFILIATED_MATCH_HELPER_H_
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace autofill {
 struct PasswordForm;
@@ -18,6 +23,14 @@
 
 class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
  public:
+  // This struct mirrors the corresponding affiliation and branding information
+  // related fields from autofill::PasswordForm.
+  struct AffiliationAndBrandingInformation {
+    std::string affiliated_web_realm;
+    std::string app_display_name;
+    GURL app_icon_url;
+  };
+
   MockAffiliatedMatchHelper();
   ~MockAffiliatedMatchHelper() override;
 
@@ -35,15 +48,16 @@
       const PasswordStore::FormDigest& expected_android_form,
       const std::vector<std::string>& results_to_return);
 
-  void ExpectCallToInjectAffiliatedWebRealms(
-      const std::vector<std::string>& results_to_inject);
+  void ExpectCallToInjectAffiliationAndBrandingInformation(
+      const std::vector<AffiliationAndBrandingInformation>& results_to_inject);
 
  private:
   MOCK_METHOD1(OnGetAffiliatedAndroidRealmsCalled,
                std::vector<std::string>(const PasswordStore::FormDigest&));
   MOCK_METHOD1(OnGetAffiliatedWebRealmsCalled,
                std::vector<std::string>(const PasswordStore::FormDigest&));
-  MOCK_METHOD0(OnInjectAffiliatedWebRealmsCalled, std::vector<std::string>());
+  MOCK_METHOD0(OnInjectAffiliationAndBrandingInformationCalled,
+               std::vector<AffiliationAndBrandingInformation>());
 
   void GetAffiliatedAndroidRealms(
       const PasswordStore::FormDigest& observed_form,
@@ -52,7 +66,7 @@
       const PasswordStore::FormDigest& android_form,
       const AffiliatedRealmsCallback& result_callback) override;
 
-  void InjectAffiliatedWebRealms(
+  void InjectAffiliationAndBrandingInformation(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
       const PasswordFormsCallback& result_callback) override;
 
diff --git a/components/password_manager/core/browser/import/password_csv_reader.cc b/components/password_manager/core/browser/import/password_csv_reader.cc
index 9b52c67..8ffcbea 100644
--- a/components/password_manager/core/browser/import/password_csv_reader.cc
+++ b/components/password_manager/core/browser/import/password_csv_reader.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 #include "components/password_manager/core/browser/import/csv_reader.h"
 
 using autofill::PasswordForm;
@@ -114,7 +115,13 @@
   password_value = base::UTF8ToUTF16(password_in_record->second);
 
   form->origin.Swap(&origin);
-  form->signon_realm = form->origin.GetOrigin().spec();
+  // |GURL::GetOrigin| returns an empty GURL for Android credentials due to the
+  // non-standard scheme ("android://"). Hence the following explicit check is
+  // necessary to set |signon_realm| correctly for both regular and Android
+  // credentials.
+  form->signon_realm = IsValidAndroidFacetURI(form->origin.spec())
+                           ? form->origin.spec()
+                           : form->origin.GetOrigin().spec();
   form->username_value.swap(username_value);
   form->password_value.swap(password_value);
   return true;
diff --git a/components/password_manager/core/browser/import/password_csv_reader_unittest.cc b/components/password_manager/core/browser/import/password_csv_reader_unittest.cc
index b3b74acbb..ea015e13 100644
--- a/components/password_manager/core/browser/import/password_csv_reader_unittest.cc
+++ b/components/password_manager/core/browser/import/password_csv_reader_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 #include "components/password_manager/core/browser/import/password_importer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,6 +37,25 @@
   EXPECT_EQ(base::UTF8ToUTF16("test1"), passwords[0].password_value);
 }
 
+TEST(PasswordCSVReaderTest, DeserializePasswords_SingleAndroid) {
+  constexpr char kCSVInput[] =
+      "Url,Username,Password\n"
+      "android://hash@com.example.android,test@gmail.com,test1\n";
+  std::vector<autofill::PasswordForm> passwords;
+  PasswordCSVReader reader;
+  EXPECT_EQ(PasswordImporter::SUCCESS,
+            reader.DeserializePasswords(kCSVInput, &passwords));
+  EXPECT_EQ(1u, passwords.size());
+  const GURL expected_origin("android://hash@com.example.android");
+
+  const autofill::PasswordForm& password = passwords.front();
+  EXPECT_EQ(expected_origin, password.origin);
+  EXPECT_EQ(expected_origin.spec(), password.signon_realm);
+  EXPECT_TRUE(IsValidAndroidFacetURI(password.signon_realm));
+  EXPECT_EQ(base::UTF8ToUTF16("test@gmail.com"), password.username_value);
+  EXPECT_EQ(base::UTF8ToUTF16("test1"), password.password_value);
+}
+
 TEST(PasswordCSVReaderTest, DeserializePasswords_TwoValid) {
   const char kCSVInput[] =
       "Url,Username,Password,Someotherfield\n"
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 6b243b99b..6047979 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -241,9 +241,10 @@
   Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
 }
 
-void PasswordStore::GetAutofillableLoginsWithAffiliatedRealms(
+void PasswordStore::GetAutofillableLoginsWithAffiliationAndBrandingInformation(
     PasswordStoreConsumer* consumer) {
-  Schedule(&PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl,
+  Schedule(&PasswordStore::
+               GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl,
            consumer);
 }
 
@@ -251,9 +252,10 @@
   Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
 }
 
-void PasswordStore::GetBlacklistLoginsWithAffiliatedRealms(
+void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformation(
     PasswordStoreConsumer* consumer) {
-  Schedule(&PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl,
+  Schedule(&PasswordStore::
+               GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl,
            consumer);
 }
 
@@ -555,8 +557,9 @@
   request->NotifyConsumerWithResults(std::move(obtained_forms));
 }
 
-void PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl(
-    std::unique_ptr<GetLoginsRequest> request) {
+void PasswordStore::
+    GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl(
+        std::unique_ptr<GetLoginsRequest> request) {
   std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
   if (!FillAutofillableLogins(&obtained_forms))
     obtained_forms.clear();
@@ -564,16 +567,10 @@
   // post a request to UI thread.
   main_thread_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&PasswordStore::InjectAffiliatedWebRealms, this,
+      base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
                  base::Passed(&obtained_forms), base::Passed(&request)));
 }
 
-void PasswordStore::NotifyLoginsWithAffiliatedRealms(
-    std::unique_ptr<GetLoginsRequest> request,
-    std::vector<std::unique_ptr<PasswordForm>> obtained_forms) {
-  request->NotifyConsumerWithResults(std::move(obtained_forms));
-}
-
 void PasswordStore::GetBlacklistLoginsImpl(
     std::unique_ptr<GetLoginsRequest> request) {
   std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
@@ -582,7 +579,7 @@
   request->NotifyConsumerWithResults(std::move(obtained_forms));
 }
 
-void PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl(
+void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl(
     std::unique_ptr<GetLoginsRequest> request) {
   std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
   if (!FillBlacklistLogins(&obtained_forms))
@@ -591,7 +588,7 @@
   // post a request to UI thread.
   main_thread_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&PasswordStore::InjectAffiliatedWebRealms, this,
+      base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
                  base::Passed(&obtained_forms), base::Passed(&request)));
 }
 
@@ -625,11 +622,11 @@
   request->NotifyConsumerWithResults(std::move(results));
 }
 
-void PasswordStore::InjectAffiliatedWebRealms(
+void PasswordStore::InjectAffiliationAndBrandingInformation(
     std::vector<std::unique_ptr<PasswordForm>> forms,
     std::unique_ptr<GetLoginsRequest> request) {
   if (affiliated_match_helper_) {
-    affiliated_match_helper_->InjectAffiliatedWebRealms(
+    affiliated_match_helper_->InjectAffiliationAndBrandingInformation(
         std::move(forms),
         base::Bind(&PasswordStore::GetLoginsRequest::NotifyConsumerWithResults,
                    base::Owned(request.release())));
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 11fe83f..0db72af 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -199,9 +199,9 @@
   // The request will be cancelled if the consumer is destroyed.
   virtual void GetAutofillableLogins(PasswordStoreConsumer* consumer);
 
-  // Same as above, but also fills in |affiliated_web_realm| for Android
-  // credentials.
-  virtual void GetAutofillableLoginsWithAffiliatedRealms(
+  // Same as above, but also fills in affiliation and branding information for
+  // Android credentials.
+  virtual void GetAutofillableLoginsWithAffiliationAndBrandingInformation(
       PasswordStoreConsumer* consumer);
 
   // Gets the complete list of PasswordForms that are blacklist entries,
@@ -209,9 +209,9 @@
   // consumer is destroyed.
   virtual void GetBlacklistLogins(PasswordStoreConsumer* consumer);
 
-  // Same as above, but also fills in |affiliated_web_realm| for Android
-  // credentials.
-  virtual void GetBlacklistLoginsWithAffiliatedRealms(
+  // Same as above, but also fills in affiliation and branding information for
+  // Android credentials.
+  virtual void GetBlacklistLoginsWithAffiliationAndBrandingInformation(
       PasswordStoreConsumer* consumer);
 
   // Reports usage metrics for the database. |sync_username| and
@@ -501,17 +501,17 @@
   // Finds all non-blacklist PasswordForms, and notifies the consumer.
   void GetAutofillableLoginsImpl(std::unique_ptr<GetLoginsRequest> request);
 
-  // Same as above, but also fills in |affiliated_web_realm| for Android
-  // credentials.
-  void GetAutofillableLoginsWithAffiliatedRealmsImpl(
+  // Same as above, but also fills in affiliation and branding information for
+  // Android credentials.
+  void GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl(
       std::unique_ptr<GetLoginsRequest> request);
 
   // Finds all blacklist PasswordForms, and notifies the consumer.
   void GetBlacklistLoginsImpl(std::unique_ptr<GetLoginsRequest> request);
 
-  // Same as above, but also fills in |affiliated_web_realm| for Android
-  // credentials.
-  void GetBlacklistLoginsWithAffiliatedRealmsImpl(
+  // Same as above, but also fills in affiliation and branding information for
+  // Android credentials.
+  void GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl(
       std::unique_ptr<GetLoginsRequest> request);
 
   // Notifies |request| about the stats for all sites.
@@ -521,12 +521,6 @@
   void NotifySiteStats(const GURL& origin_domain,
                        std::unique_ptr<GetLoginsRequest> request);
 
-  // Notifies |request| about the autofillable logins with affiliated web
-  // realms for Android credentials.
-  void NotifyLoginsWithAffiliatedRealms(
-      std::unique_ptr<GetLoginsRequest> request,
-      std::vector<std::unique_ptr<autofill::PasswordForm>> obtained_forms);
-
   // Extended version of GetLoginsImpl that also returns credentials stored for
   // the specified affiliated Android applications. That is, it finds all
   // PasswordForms with a signon_realm that is either:
@@ -539,9 +533,9 @@
       std::unique_ptr<GetLoginsRequest> request,
       const std::vector<std::string>& additional_android_realms);
 
-  // Retrieves and fills in |affiliated_web_realm| values for Android
+  // Retrieves and fills in affiliation and branding information for Android
   // credentials in |forms|. Called on the main thread.
-  void InjectAffiliatedWebRealms(
+  void InjectAffiliationAndBrandingInformation(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
       std::unique_ptr<GetLoginsRequest> request);
 
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index f536b89c..6d2eab58 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -79,6 +79,10 @@
     "android://hash@com.example.three.android/";
 constexpr const char kTestUnrelatedAndroidRealm[] =
     "android://hash@com.notexample.android/";
+constexpr const char kTestAndroidName1[] = "Example Android App 1";
+constexpr const char kTestAndroidIconURL1[] = "https://example.com/icon_1.png";
+constexpr const char kTestAndroidName2[] = "Example Android App 2";
+constexpr const char kTestAndroidIconURL2[] = "https://example.com/icon_2.png";
 
 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
  public:
@@ -813,28 +817,18 @@
   }
 }
 
-TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
-  /* clang-format off */
+TEST_F(PasswordStoreTest, GetLoginsWithAffiliationAndBrandingInformation) {
   static const PasswordFormData kTestCredentials[] = {
-      {PasswordForm::SCHEME_HTML,
-       kTestAndroidRealm1,
-       "", "", L"", L"", L"",
-       L"username_value_1",
-       L"", true, 1},
-      {PasswordForm::SCHEME_HTML,
-       kTestAndroidRealm2,
-       "", "", L"", L"", L"",
-       L"username_value_2",
-       L"", true, 1},
-      {PasswordForm::SCHEME_HTML,
-       kTestAndroidRealm3,
-       "", "", L"", L"", L"",
-       L"username_value_3",
-       L"", true, 1}};
-  /* clang-format on */
+      {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
+       L"username_value_1", L"", true, 1},
+      {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
+       L"username_value_2", L"", true, 1},
+      {PasswordForm::SCHEME_HTML, kTestAndroidRealm3, "", "", L"", L"", L"",
+       L"username_value_3", L"", true, 1},
+      {PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"", L"",
+       L"", L"username_value_4", L"", true, 1}};
 
-  const bool kFalseTrue[] = {false, true};
-  for (bool blacklisted : kFalseTrue) {
+  for (bool blacklisted : {false, true}) {
     SCOPED_TRACE(testing::Message("use blacklisted logins: ") << blacklisted);
     scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
         base::SequencedTaskRunnerHandle::Get(),
@@ -845,44 +839,53 @@
                                       base::Closure());
 
     std::vector<std::unique_ptr<PasswordForm>> all_credentials;
-    for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
+    for (const auto& test_credential : kTestCredentials) {
       all_credentials.push_back(
-          CreatePasswordFormFromDataForTesting(kTestCredentials[i]));
-      if (blacklisted)
-        all_credentials.back()->blacklisted_by_user = true;
+          CreatePasswordFormFromDataForTesting(test_credential));
+      all_credentials.back()->blacklisted_by_user = blacklisted;
       store->AddLogin(*all_credentials.back());
       base::RunLoop().RunUntilIdle();
     }
 
     MockPasswordStoreConsumer mock_consumer;
     std::vector<std::unique_ptr<PasswordForm>> expected_results;
-    for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
-      expected_results.push_back(
-          base::MakeUnique<PasswordForm>(*all_credentials[i]));
+    for (const auto& credential : all_credentials)
+      expected_results.push_back(base::MakeUnique<PasswordForm>(*credential));
+
+    std::vector<MockAffiliatedMatchHelper::AffiliationAndBrandingInformation>
+        affiliation_info_for_results = {
+            {kTestWebRealm1, kTestAndroidName1, GURL(kTestAndroidIconURL1)},
+            {kTestWebRealm2, kTestAndroidName2, GURL(kTestAndroidIconURL2)},
+            {/* Pretend affiliation or branding info is unavailable. */},
+            {/* Pretend affiliation or branding info is unavailable. */}};
+
+    auto mock_helper = base::MakeUnique<MockAffiliatedMatchHelper>();
+    mock_helper->ExpectCallToInjectAffiliationAndBrandingInformation(
+        affiliation_info_for_results);
+    store->SetAffiliatedMatchHelper(std::move(mock_helper));
+    for (size_t i = 0; i < expected_results.size(); ++i) {
+      expected_results[i]->affiliated_web_realm =
+          affiliation_info_for_results[i].affiliated_web_realm;
+      expected_results[i]->app_display_name =
+          affiliation_info_for_results[i].app_display_name;
+      expected_results[i]->app_icon_url =
+          affiliation_info_for_results[i].app_icon_url;
     }
 
-    MockAffiliatedMatchHelper* mock_helper = new MockAffiliatedMatchHelper;
-    store->SetAffiliatedMatchHelper(base::WrapUnique(mock_helper));
-
-    std::vector<std::string> affiliated_web_realms;
-    affiliated_web_realms.push_back(kTestWebRealm1);
-    affiliated_web_realms.push_back(kTestWebRealm2);
-    affiliated_web_realms.push_back(std::string());
-    mock_helper->ExpectCallToInjectAffiliatedWebRealms(affiliated_web_realms);
-    for (size_t i = 0; i < expected_results.size(); ++i)
-      expected_results[i]->affiliated_web_realm = affiliated_web_realms[i];
-
     EXPECT_CALL(mock_consumer,
                 OnGetPasswordStoreResultsConstRef(
                     UnorderedPasswordFormElementsAre(&expected_results)));
-    if (blacklisted)
-      store->GetBlacklistLoginsWithAffiliatedRealms(&mock_consumer);
-    else
-      store->GetAutofillableLoginsWithAffiliatedRealms(&mock_consumer);
+    if (blacklisted) {
+      store->GetBlacklistLoginsWithAffiliationAndBrandingInformation(
+          &mock_consumer);
+    } else {
+      store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
+          &mock_consumer);
+    }
 
-    // Since GetAutofillableLoginsWithAffiliatedRealms schedules a request for
-    // affiliated realms to UI thread, don't shutdown UI thread until there are
-    // no tasks in the UI queue.
+    // Since GetAutofillableLoginsWithAffiliationAndBrandingInformation
+    // schedules a request for affiliation information to UI thread, don't
+    // shutdown UI thread until there are no tasks in the UI queue.
     base::RunLoop().RunUntilIdle();
     store->ShutdownOnUIThread();
     base::RunLoop().RunUntilIdle();
diff --git a/components/payments/core/subkey_requester.cc b/components/payments/core/subkey_requester.cc
index 513fc54..f4dfbc87 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 c3d712b3..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..8cb219a1 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/toolbar/BUILD.gn b/components/toolbar/BUILD.gn
index 9416363..6f2271d7 100644
--- a/components/toolbar/BUILD.gn
+++ b/components/toolbar/BUILD.gn
@@ -24,6 +24,7 @@
     "https_valid.icon",
     "https_valid_in_chip.1x.icon",
     "https_valid_in_chip.icon",
+    "offline_pin.icon",
     "product.1x.icon",
     "product.icon",
     "star_active.icon",
diff --git a/components/toolbar/toolbar_model_impl.cc b/components/toolbar/toolbar_model_impl.cc
index c24a388..8d3b2ac 100644
--- a/components/toolbar/toolbar_model_impl.cc
+++ b/components/toolbar/toolbar_model_impl.cc
@@ -79,6 +79,9 @@
   if (icon_override)
     return *icon_override;
 
+  if (IsOfflinePage())
+    return toolbar::kOfflinePinIcon;
+
   switch (GetSecurityLevel(false)) {
     case security_state::NONE:
     case security_state::HTTP_SHOW_WARNING:
@@ -121,6 +124,9 @@
 }
 
 base::string16 ToolbarModelImpl::GetSecureVerboseText() const {
+  if (IsOfflinePage())
+    return l10n_util::GetStringUTF16(IDS_OFFLINE_VERBOSE_STATE);
+
   switch (GetSecurityLevel(false)) {
     case security_state::HTTP_SHOW_WARNING:
       return l10n_util::GetStringUTF16(IDS_NOT_SECURE_VERBOSE_STATE);
diff --git a/components/toolbar/vector_icons/offline_pin.icon b/components/toolbar/vector_icons/offline_pin.icon
new file mode 100644
index 0000000..935b7332
--- /dev/null
+++ b/components/toolbar/vector_icons/offline_pin.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 12, 2,
+CUBIC_TO, 6.5f, 2, 2, 6.5f, 2, 12,
+R_CUBIC_TO, 0, 5.5f, 4.5f, 10, 10, 10,
+R_CUBIC_TO, 5.5f, 0, 10, -4.5f, 10, -10,
+R_CUBIC_TO, 0, -5.5f, -4.5f, -10, -10, -10,
+CLOSE,
+R_MOVE_TO, 5, 16,
+H_LINE_TO, 7,
+R_V_LINE_TO, -2,
+R_H_LINE_TO, 10,
+R_V_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, -6.7f, -4,
+LINE_TO, 7, 10.7f,
+R_LINE_TO, 1.4f, -1.4f,
+R_LINE_TO, 1.9f, 1.9f,
+R_LINE_TO, 5.3f, -5.3f,
+LINE_TO, 17, 7.3f,
+LINE_TO, 10.3f, 14,
+CLOSE,
+END
diff --git a/components/translate/core/browser/translate_url_fetcher.cc b/components/translate/core/browser/translate_url_fetcher.cc
index 0a058105..ef64ca09 100644
--- a/components/translate/core/browser/translate_url_fetcher.cc
+++ b/components/translate/core/browser/translate_url_fetcher.cc
@@ -23,7 +23,7 @@
 }  // namespace
 
 TranslateURLFetcher::TranslateURLFetcher(int id)
-    : id_(id), state_(IDLE), retry_count_(0) {}
+    : id_(id), state_(IDLE), retry_count_(0), max_retry_on_5xx_(0) {}
 
 TranslateURLFetcher::~TranslateURLFetcher() {}
 
diff --git a/components/ui_devtools/views/ui_devtools_dom_agent.cc b/components/ui_devtools/views/ui_devtools_dom_agent.cc
index 3adba64e..c4c3cbf 100644
--- a/components/ui_devtools/views/ui_devtools_dom_agent.cc
+++ b/components/ui_devtools/views/ui_devtools_dom_agent.cc
@@ -144,8 +144,8 @@
 }
 
 ui_devtools::protocol::Response UIDevToolsDOMAgent::hideHighlight() {
-  if (widget_for_highlighting_ && widget_for_highlighting_->IsVisible())
-    widget_for_highlighting_->Hide();
+  if (layer_for_highlighting_ && layer_for_highlighting_->visible())
+    layer_for_highlighting_->SetVisible(false);
   return ui_devtools::protocol::Response::OK();
 }
 
@@ -193,11 +193,6 @@
     observer.OnNodeBoundsChanged(ui_element->node_id());
 }
 
-bool UIDevToolsDOMAgent::IsHighlightingWindow(aura::Window* window) {
-  return widget_for_highlighting_ &&
-         GetWidgetFromWindow(window) == widget_for_highlighting_.get();
-}
-
 void UIDevToolsDOMAgent::AddObserver(UIDevToolsDOMAgentObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -328,41 +323,25 @@
 
 void UIDevToolsDOMAgent::Reset() {
   is_building_tree_ = false;
-  widget_for_highlighting_.reset();
+  layer_for_highlighting_.reset();
   window_element_root_.reset();
   node_id_to_ui_element_.clear();
   observers_.Clear();
 }
 
-void UIDevToolsDOMAgent::InitializeHighlightingWidget() {
-  DCHECK(!widget_for_highlighting_);
-  widget_for_highlighting_.reset(new views::Widget);
-  views::Widget::InitParams params;
-  params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
-  params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.opacity = views::Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW;
-  params.name = "HighlightingWidget";
-  params.parent = root_windows()[0];
-  params.keep_on_top = true;
-  params.accept_events = false;
-  widget_for_highlighting_->Init(params);
-}
-
 void UIDevToolsDOMAgent::UpdateHighlight(
     const std::pair<aura::Window*, gfx::Rect>& window_and_bounds,
-    SkColor background,
-    SkColor border) {
-  constexpr int kBorderThickness = 1;
-  views::View* root_view = widget_for_highlighting_->GetRootView();
-  root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border));
-  root_view->SetBackground(views::CreateSolidBackground(background));
+    SkColor background) {
+  layer_for_highlighting_->SetColor(background);
+
   display::Display display =
       display::Screen::GetScreen()->GetDisplayNearestWindow(
           window_and_bounds.first);
   aura::Window* root = window_and_bounds.first->GetRootWindow();
-  if (root != widget_for_highlighting_->GetNativeWindow()->GetRootWindow())
-    root->AddChild(widget_for_highlighting_->GetNativeWindow());
+  if (root->layer() != layer_for_highlighting_->parent())
+    root->layer()->Add(layer_for_highlighting_.get());
+  else
+    root->layer()->StackAtTop(layer_for_highlighting_.get());
 
   aura::client::ScreenPositionClient* screen_position_client =
       aura::client::GetScreenPositionClient(root);
@@ -371,15 +350,18 @@
   gfx::Point origin = bounds.origin();
   screen_position_client->ConvertPointFromScreen(root, &origin);
   bounds.set_origin(origin);
-  widget_for_highlighting_->GetNativeWindow()->SetBounds(bounds);
+  layer_for_highlighting_->SetBounds(bounds);
 }
 
 ui_devtools::protocol::Response UIDevToolsDOMAgent::HighlightNode(
     std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
         highlight_config,
     int node_id) {
-  if (!widget_for_highlighting_)
-    InitializeHighlightingWidget();
+  if (!layer_for_highlighting_) {
+    layer_for_highlighting_.reset(
+        new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR));
+    layer_for_highlighting_->set_name("HighlightingLayer");
+  }
 
   std::pair<aura::Window*, gfx::Rect> window_and_bounds =
       node_id_to_ui_element_.count(node_id)
@@ -389,14 +371,12 @@
   if (!window_and_bounds.first) {
     return ui_devtools::protocol::Response::Error("No node found with that id");
   }
-  SkColor border_color =
-      RGBAToSkColor(highlight_config->getBorderColor(nullptr));
   SkColor content_color =
       RGBAToSkColor(highlight_config->getContentColor(nullptr));
-  UpdateHighlight(window_and_bounds, content_color, border_color);
+  UpdateHighlight(window_and_bounds, content_color);
 
-  if (!widget_for_highlighting_->IsVisible())
-    widget_for_highlighting_->Show();
+  if (!layer_for_highlighting_->visible())
+    layer_for_highlighting_->SetVisible(true);
 
   return ui_devtools::protocol::Response::OK();
 }
diff --git a/components/ui_devtools/views/ui_devtools_dom_agent.h b/components/ui_devtools/views/ui_devtools_dom_agent.h
index 701547f6..cdd2382 100644
--- a/components/ui_devtools/views/ui_devtools_dom_agent.h
+++ b/components/ui_devtools/views/ui_devtools_dom_agent.h
@@ -49,7 +49,6 @@
   void OnUIElementReordered(UIElement* parent, UIElement* child) override;
   void OnUIElementRemoved(UIElement* ui_element) override;
   void OnUIElementBoundsChanged(UIElement* ui_element) override;
-  bool IsHighlightingWindow(aura::Window* window) override;
 
   void AddObserver(UIDevToolsDOMAgentObserver* observer);
   void RemoveObserver(UIDevToolsDOMAgentObserver* observer);
@@ -82,8 +81,7 @@
   void InitializeHighlightingWidget();
   void UpdateHighlight(
       const std::pair<aura::Window*, gfx::Rect>& window_and_bounds,
-      SkColor background,
-      SkColor border);
+      SkColor background);
   ui_devtools::protocol::Response HighlightNode(
       std::unique_ptr<ui_devtools::protocol::DOM::HighlightConfig>
           highlight_config,
@@ -92,7 +90,7 @@
   bool is_building_tree_;
   std::unique_ptr<UIElement> window_element_root_;
   std::unordered_map<int, UIElement*> node_id_to_ui_element_;
-  std::unique_ptr<views::Widget> widget_for_highlighting_;
+  std::unique_ptr<ui::Layer> layer_for_highlighting_;
   std::vector<aura::Window*> root_windows_;
   base::ObserverList<UIDevToolsDOMAgentObserver> observers_;
 
diff --git a/components/ui_devtools/views/ui_devtools_unittest.cc b/components/ui_devtools/views/ui_devtools_unittest.cc
index e0fed67d..fbd45920 100644
--- a/components/ui_devtools/views/ui_devtools_unittest.cc
+++ b/components/ui_devtools/views/ui_devtools_unittest.cc
@@ -139,11 +139,10 @@
   return -1;
 }
 
-aura::Window* GetHighlightingWindow(aura::Window* root_window) {
-  const aura::Window::Windows& overlay_windows = root_window->children();
-  for (aura::Window* window : overlay_windows) {
-    if (window->GetName() == "HighlightingWidget")
-      return window;
+ui::Layer* GetHighlightingLayer(aura::Window* highlight_window) {
+  for (auto* layer : highlight_window->layer()->children()) {
+    if (layer->name() == "HighlightingLayer")
+      return layer;
   }
   NOTREACHED();
   return nullptr;
@@ -167,15 +166,12 @@
       .build();
 }
 
-void ExpectHighlighted(const gfx::Rect& bounds, aura::Window* root_window) {
-  aura::Window* highlighting_window = GetHighlightingWindow(root_window);
-  EXPECT_TRUE(highlighting_window->IsVisible());
-  EXPECT_EQ(bounds, highlighting_window->GetBoundsInScreen());
-  EXPECT_EQ(kBackgroundColor,
-            views::Widget::GetWidgetForNativeView(highlighting_window)
-                ->GetRootView()
-                ->background()
-                ->get_color());
+void ExpectHighlighted(const gfx::Rect& bounds,
+                       aura::Window* highlight_window) {
+  ui::Layer* highlighting_layer = GetHighlightingLayer(highlight_window);
+  EXPECT_TRUE(highlighting_layer->visible());
+  EXPECT_EQ(bounds, highlighting_layer->bounds());
+  EXPECT_EQ(kBackgroundColor, highlighting_layer->GetTargetColor());
 }
 
 }  // namespace
@@ -314,8 +310,8 @@
     DCHECK_LE(root_window_index,
               static_cast<int>(dom_agent()->root_windows().size()));
     ASSERT_FALSE(
-        GetHighlightingWindow(dom_agent()->root_windows()[root_window_index])
-            ->IsVisible());
+        GetHighlightingLayer(dom_agent()->root_windows()[root_window_index])
+            ->visible());
   }
 
   FakeFrontendChannel* frontend_channel() {
@@ -726,7 +722,7 @@
 
   // Highlight non-existent node
   HighlightNode(10000);
-  EXPECT_FALSE(GetHighlightingWindow(GetPrimaryRootWindow())->IsVisible());
+  EXPECT_FALSE(GetHighlightingLayer(GetPrimaryRootWindow())->visible());
 }
 
 int GetNodeIdFromWindow(ui_devtools::UIElement* ui_element,
diff --git a/components/ui_devtools/views/ui_element_delegate.h b/components/ui_devtools/views/ui_element_delegate.h
index 1f49c60f..966a71e 100644
--- a/components/ui_devtools/views/ui_element_delegate.h
+++ b/components/ui_devtools/views/ui_element_delegate.h
@@ -30,9 +30,6 @@
   // Update CSS agent when bounds change.
   virtual void OnUIElementBoundsChanged(UIElement* ui_element) = 0;
 
-  // Return |window| highlighting status.
-  virtual bool IsHighlightingWindow(aura::Window* window) = 0;
-
   DISALLOW_COPY_AND_ASSIGN(UIElementDelegate);
 };
 
diff --git a/components/ui_devtools/views/window_element.cc b/components/ui_devtools/views/window_element.cc
index 7faa860..951d137 100644
--- a/components/ui_devtools/views/window_element.cc
+++ b/components/ui_devtools/views/window_element.cc
@@ -46,8 +46,6 @@
 void WindowElement::OnWindowHierarchyChanged(
     const aura::WindowObserver::HierarchyChangeParams& params) {
   if (window_ == params.new_parent && params.receiver == params.new_parent) {
-    if (delegate()->IsHighlightingWindow(params.target))
-      return;
     AddChild(new WindowElement(params.target, delegate(), this),
              children().empty() ? nullptr : children().back());
   }
diff --git a/components/ukm/BUILD.gn b/components/ukm/BUILD.gn
index 165a341..887ea04 100644
--- a/components/ukm/BUILD.gn
+++ b/components/ukm/BUILD.gn
@@ -89,6 +89,7 @@
     "//base",
     "//components/metrics:test_support",
     "//components/prefs:test_support",
+    "//testing/gtest:gtest",
   ]
 }
 
diff --git a/components/ukm/test_ukm_recorder.cc b/components/ukm/test_ukm_recorder.cc
index bd04810..cab00fa 100644
--- a/components/ukm/test_ukm_recorder.cc
+++ b/components/ukm/test_ukm_recorder.cc
@@ -4,12 +4,53 @@
 
 #include "components/ukm/test_ukm_recorder.h"
 
+#include <algorithm>
+#include <iterator>
+
 #include "base/logging.h"
 #include "base/metrics/metrics_hashes.h"
 #include "components/ukm/ukm_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace ukm {
 
+namespace {
+
+// Provides a single merged ukm::mojom::UkmEntry proto that contains all metrics
+// from the given |entries|. |entries| must be non-empty, and all |entries| must
+// have the same |source_id| and |event_hash|.
+mojom::UkmEntryPtr GetMergedEntry(
+    const std::vector<const mojom::UkmEntry*>& entries) {
+  EXPECT_FALSE(entries.empty());
+  mojom::UkmEntryPtr merged_entry = mojom::UkmEntry::New();
+  for (const auto* entry : entries) {
+    if (merged_entry->event_hash) {
+      EXPECT_EQ(merged_entry->source_id, entry->source_id);
+      EXPECT_EQ(merged_entry->event_hash, entry->event_hash);
+    } else {
+      merged_entry->event_hash = entry->event_hash;
+      merged_entry->source_id = entry->source_id;
+    }
+    for (const auto& metric : entry->metrics) {
+      merged_entry->metrics.emplace_back(metric->Clone());
+    }
+  }
+  return merged_entry;
+}
+
+std::vector<int64_t> GetValuesForMetric(const mojom::UkmEntry* entry,
+                                        const char* metric_name) {
+  std::vector<int64_t> values;
+  const uint64_t metric_hash = base::HashMetricName(metric_name);
+  for (const auto& metric : entry->metrics) {
+    if (metric->metric_hash == metric_hash)
+      values.push_back(metric->value);
+  }
+  return values;
+}
+
+}  // namespace
+
 TestUkmRecorder::TestUkmRecorder() {
   EnableRecording();
   UkmRecorder::Set(this);
@@ -30,8 +71,18 @@
   return source;
 }
 
+std::vector<const UkmSource*> TestUkmRecorder::GetSourcesForUrl(
+    const char* url) const {
+  std::vector<const UkmSource*> matching_sources;
+  for (const auto& kv : sources()) {
+    if (kv.second->url() == url)
+      matching_sources.push_back(kv.second.get());
+  }
+  return matching_sources;
+}
+
 const UkmSource* TestUkmRecorder::GetSourceForSourceId(
-    ukm::SourceId source_id) const {
+    SourceId source_id) const {
   const UkmSource* source = nullptr;
   for (const auto& kv : sources()) {
     if (kv.second->id() == source_id) {
@@ -67,4 +118,126 @@
   return nullptr;
 }
 
+std::vector<const mojom::UkmEntry*> TestUkmRecorder::GetEntriesForSourceID(
+    SourceId source_id,
+    const char* event_name) const {
+  const uint64_t event_hash = base::HashMetricName(event_name);
+  std::vector<const mojom::UkmEntry*> entries;
+  for (size_t i = 0; i < entries_count(); ++i) {
+    const mojom::UkmEntry* entry = GetEntry(i);
+    if (entry->source_id == source_id && entry->event_hash == event_hash) {
+      entries.push_back(entry);
+    }
+  }
+  return entries;
+}
+
+mojom::UkmEntryPtr TestUkmRecorder::GetMergedEntryForSourceID(
+    SourceId source_id,
+    const char* event_name) const {
+  mojom::UkmEntryPtr entry =
+      GetMergedEntry(GetEntriesForSourceID(source_id, event_name));
+  EXPECT_EQ(source_id, entry->source_id);
+  EXPECT_EQ(base::HashMetricName(event_name), entry->event_hash);
+  return entry;
+}
+
+bool TestUkmRecorder::HasEntry(const UkmSource& source,
+                               const char* event_name) const {
+  return CountEntries(source, event_name) > 0;
+}
+
+int TestUkmRecorder::CountEntries(const UkmSource& source,
+                                  const char* event_name) const {
+  return GetEntriesForSourceID(source.id(), event_name).size();
+}
+
+void TestUkmRecorder::ExpectEntry(
+    const UkmSource& source,
+    const char* event_name,
+    const std::vector<std::pair<const char*, int64_t>>& expected_metrics)
+    const {
+  // Produce a sorted view of the expected metrics, since order is not
+  // significant.
+  std::vector<std::pair<uint64_t, int64_t>> sorted_expected_metrics;
+  std::transform(expected_metrics.begin(), expected_metrics.end(),
+                 std::back_inserter(sorted_expected_metrics),
+                 [](const std::pair<const char*, int64_t>& metric) {
+                   return std::make_pair(base::HashMetricName(metric.first),
+                                         metric.second);
+                 });
+  std::sort(sorted_expected_metrics.begin(), sorted_expected_metrics.end());
+
+  std::vector<const mojom::UkmEntry*> candidate_entries =
+      GetEntriesForSourceID(source.id(), event_name);
+
+  // Produce a view of each matching entry's metrics that can be compared with
+  // sorted_expected_metrics.
+  std::vector<std::vector<std::pair<uint64_t, int64_t>>> candidate_metrics;
+  std::transform(
+      candidate_entries.begin(), candidate_entries.end(),
+      std::back_inserter(candidate_metrics),
+      [](const mojom::UkmEntry* candidate_entry) {
+        std::vector<std::pair<uint64_t, int64_t>> metrics;
+        std::transform(
+            candidate_entry->metrics.begin(), candidate_entry->metrics.end(),
+            std::back_inserter(metrics), [](const mojom::UkmMetricPtr& metric) {
+              return std::make_pair(metric->metric_hash, metric->value);
+            });
+        std::sort(metrics.begin(), metrics.end());
+        return metrics;
+      });
+
+  if (std::find(candidate_metrics.begin(), candidate_metrics.end(),
+                sorted_expected_metrics) == candidate_metrics.end()) {
+    FAIL() << "Failed to find metrics for event: " << event_name;
+  }
+}
+
+int TestUkmRecorder::CountMetricsForEventName(const UkmSource& source,
+                                              const char* event_name) const {
+  mojom::UkmEntryPtr entry = GetMergedEntryForSourceID(source.id(), event_name);
+  return entry.get() ? entry->metrics.size() : 0;
+}
+
+bool TestUkmRecorder::HasMetric(const UkmSource& source,
+                                const char* event_name,
+                                const char* metric_name) const {
+  return CountMetrics(source, event_name, metric_name) > 0;
+}
+
+int TestUkmRecorder::CountMetrics(const UkmSource& source,
+                                  const char* event_name,
+                                  const char* metric_name) const {
+  mojom::UkmEntryPtr entry = GetMergedEntryForSourceID(source.id(), event_name);
+  return GetValuesForMetric(entry.get(), metric_name).size();
+}
+
+void TestUkmRecorder::ExpectMetric(const UkmSource& source,
+                                   const char* event_name,
+                                   const char* metric_name,
+                                   int64_t expected_value) const {
+  ExpectMetrics(source, event_name, metric_name, {expected_value});
+}
+
+void TestUkmRecorder::ExpectMetrics(
+    const UkmSource& source,
+    const char* event_name,
+    const char* metric_name,
+    const std::vector<int64_t>& expected_values) const {
+  mojom::UkmEntryPtr entry = GetMergedEntryForSourceID(source.id(), event_name);
+
+  // Make sure both vectors are sorted before comparing, since order is not
+  // significant.
+  std::vector<int64_t> sorted_expected_values(expected_values);
+  std::sort(sorted_expected_values.begin(), sorted_expected_values.end());
+
+  std::vector<int64_t> actual_values =
+      GetValuesForMetric(entry.get(), metric_name);
+  std::sort(actual_values.begin(), actual_values.end());
+
+  EXPECT_EQ(actual_values, sorted_expected_values)
+      << "Failed to find expected_values for metric: " << metric_name;
+}
+
 }  // namespace ukm
diff --git a/components/ukm/test_ukm_recorder.h b/components/ukm/test_ukm_recorder.h
index ef989b9d..fb998ff 100644
--- a/components/ukm/test_ukm_recorder.h
+++ b/components/ukm/test_ukm_recorder.h
@@ -6,10 +6,16 @@
 #define COMPONENTS_UKM_TEST_UKM_RECORDER_H_
 
 #include <stddef.h>
-#include <memory>
 
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "components/ukm/ukm_recorder_impl.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
 
 namespace ukm {
 
@@ -25,16 +31,85 @@
     return sources();
   }
   const UkmSource* GetSourceForUrl(const char* url) const;
+  std::vector<const ukm::UkmSource*> GetSourcesForUrl(const char* url) const;
   const UkmSource* GetSourceForSourceId(ukm::SourceId source_id) const;
 
   size_t entries_count() const { return entries().size(); }
+
+  // Returns whether the given UKM |source| has an entry with the given
+  // |event_name|.
+  bool HasEntry(const ukm::UkmSource& source,
+                const char* event_name) const WARN_UNUSED_RESULT;
+
+  // Returns the number of metrics recorded for the given UKM |source| and
+  // |event_name|.
+  int CountMetricsForEventName(const ukm::UkmSource& source,
+                               const char* event_name) const;
+
+  // Returns whether a metric with the given |metric_name| was recorded for the
+  // given UKM |source| and |event_name|.
+  bool HasMetric(const ukm::UkmSource& source,
+                 const char* event_name,
+                 const char* metric_name) const WARN_UNUSED_RESULT;
+
+  // Returns the number of metrics recorded with the given |metric_name|, for
+  // the given UKM |source| and |event_name|.
+  int CountMetrics(const ukm::UkmSource& source,
+                   const char* event_name,
+                   const char* metric_name) const WARN_UNUSED_RESULT;
+
+  // Expects that a single metric was recorded with the given |expected_value|,
+  // for the given |source| and |event_name|. This is shorthand for calling
+  // ExpectMetrics with a single value in the expected values vector.
+  void ExpectMetric(const ukm::UkmSource& source,
+                    const char* event_name,
+                    const char* metric_name,
+                    int64_t expected_value) const;
+
+  // Expects that metrics were recorded with the given |expected_values|, for
+  // the given |source| and |event_name|. The order of |expected_values| is not
+  // significant.
+  void ExpectMetrics(const ukm::UkmSource& source,
+                     const char* event_name,
+                     const char* metric_name,
+                     const std::vector<int64_t>& expected_values) const;
+
+  // UKM entries that may be recorded multiple times for a single source may
+  // need to verify that an expected number of UKM entries were logged. The
+  // utility methods below can be used to verify expected entries. UKM entries
+  // that aren't recorded multiple times per source should prefer using
+  // HasMetric/CountMetrics/ExpectMetric(s) above.
+
+  // Returns the number of entries recorded with the given |event_name|, for the
+  // given UKM |source|.
+  int CountEntries(const ukm::UkmSource& source, const char* event_name) const;
+
+  // Expects that an entry with the given |expected_metrics| was recorded, for
+  // the given |source| and |event_name|. The order of |expected_metrics| is not
+  // significant. |expected_metrics| contains (metric name,metric value) pairs.
+  void ExpectEntry(const ukm::UkmSource& source,
+                   const char* event_name,
+                   const std::vector<std::pair<const char*, int64_t>>&
+                       expected_metrics) const;
+
+  // Deprecated.
   const mojom::UkmEntry* GetEntry(size_t entry_num) const;
+  // Deprecated.
   const mojom::UkmEntry* GetEntryForEntryName(const char* entry_name) const;
 
+  // Deprecated.
   static const mojom::UkmMetric* FindMetric(const mojom::UkmEntry* entry,
                                             const char* metric_name);
 
  private:
+  ukm::mojom::UkmEntryPtr GetMergedEntryForSourceID(
+      ukm::SourceId source_id,
+      const char* event_name) const;
+
+  std::vector<const ukm::mojom::UkmEntry*> GetEntriesForSourceID(
+      ukm::SourceId source_id,
+      const char* event_name) const;
+
   DISALLOW_COPY_AND_ASSIGN(TestUkmRecorder);
 };
 
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/client/BUILD.gn b/components/viz/client/BUILD.gn
index d96a543..a2ce3fb 100644
--- a/components/viz/client/BUILD.gn
+++ b/components/viz/client/BUILD.gn
@@ -17,6 +17,7 @@
     "//cc",
     "//cc/ipc:interfaces",
     "//cc/surfaces",
+    "//components/viz/common",
     "//mojo/public/cpp/bindings",
   ]
 }
diff --git a/components/viz/client/client_layer_tree_frame_sink.cc b/components/viz/client/client_layer_tree_frame_sink.cc
index 795f7d2..2a5dc333 100644
--- a/components/viz/client/client_layer_tree_frame_sink.cc
+++ b/components/viz/client/client_layer_tree_frame_sink.cc
@@ -10,6 +10,7 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/layer_tree_frame_sink_client.h"
 #include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 
 namespace viz {
 
@@ -17,7 +18,7 @@
     scoped_refptr<cc::ContextProvider> context_provider,
     scoped_refptr<cc::ContextProvider> worker_context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    cc::SharedBitmapManager* shared_bitmap_manager,
+    SharedBitmapManager* shared_bitmap_manager,
     std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source,
     cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
     cc::mojom::CompositorFrameSinkClientRequest client_request,
diff --git a/components/viz/client/client_layer_tree_frame_sink.h b/components/viz/client/client_layer_tree_frame_sink.h
index 5a380bb..4946db4 100644
--- a/components/viz/client/client_layer_tree_frame_sink.h
+++ b/components/viz/client/client_layer_tree_frame_sink.h
@@ -18,6 +18,7 @@
 namespace viz {
 
 class LocalSurfaceIdProvider;
+class SharedBitmapManager;
 
 class ClientLayerTreeFrameSink : public cc::LayerTreeFrameSink,
                                  public cc::mojom::CompositorFrameSinkClient,
@@ -27,7 +28,7 @@
       scoped_refptr<cc::ContextProvider> context_provider,
       scoped_refptr<cc::ContextProvider> worker_context_provider,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      cc::SharedBitmapManager* shared_bitmap_manager,
+      SharedBitmapManager* shared_bitmap_manager,
       std::unique_ptr<cc::SyntheticBeginFrameSource>
           synthetic_begin_frame_source,
       cc::mojom::CompositorFrameSinkPtrInfo compositor_frame_sink_info,
diff --git a/components/viz/client/client_shared_bitmap_manager.cc b/components/viz/client/client_shared_bitmap_manager.cc
index 0651549..2a35491 100644
--- a/components/viz/client/client_shared_bitmap_manager.cc
+++ b/components/viz/client/client_shared_bitmap_manager.cc
@@ -21,15 +21,15 @@
 
 namespace {
 
-class ClientSharedBitmap : public cc::SharedBitmap {
+class ClientSharedBitmap : public SharedBitmap {
  public:
   ClientSharedBitmap(
       scoped_refptr<
           cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
           shared_bitmap_allocation_notifier,
       base::SharedMemory* shared_memory,
-      const cc::SharedBitmapId& id)
-      : cc::SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
+      const SharedBitmapId& id)
+      : SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
         shared_bitmap_allocation_notifier_(
             std::move(shared_bitmap_allocation_notifier)) {}
 
@@ -38,7 +38,7 @@
           cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
           shared_bitmap_allocation_notifier,
       std::unique_ptr<base::SharedMemory> shared_memory_holder,
-      const cc::SharedBitmapId& id)
+      const SharedBitmapId& id)
       : ClientSharedBitmap(std::move(shared_bitmap_allocation_notifier),
                            shared_memory_holder.get(),
                            id) {
@@ -49,7 +49,7 @@
     (*shared_bitmap_allocation_notifier_)->DidDeleteSharedBitmap(id());
   }
 
-  // cc::SharedBitmap:
+  // SharedBitmap:
   base::SharedMemoryHandle GetSharedMemoryHandle() const override {
     if (!shared_memory_holder_)
       return base::SharedMemoryHandle();
@@ -118,14 +118,14 @@
 
 ClientSharedBitmapManager::~ClientSharedBitmapManager() {}
 
-std::unique_ptr<cc::SharedBitmap>
-ClientSharedBitmapManager::AllocateSharedBitmap(const gfx::Size& size) {
+std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::AllocateSharedBitmap(
+    const gfx::Size& size) {
   TRACE_EVENT2("renderer", "ClientSharedBitmapManager::AllocateSharedBitmap",
                "width", size.width(), "height", size.height());
   size_t memory_size;
-  if (!cc::SharedBitmap::SizeInBytes(size, &memory_size))
+  if (!SharedBitmap::SizeInBytes(size, &memory_size))
     return nullptr;
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
   std::unique_ptr<base::SharedMemory> memory =
       AllocateSharedMemory(memory_size);
   if (!memory || !memory->Map(memory_size))
@@ -141,17 +141,17 @@
       shared_bitmap_allocation_notifier_, std::move(memory), id);
 }
 
-std::unique_ptr<cc::SharedBitmap>
-ClientSharedBitmapManager::GetSharedBitmapFromId(const gfx::Size&,
-                                                 const cc::SharedBitmapId&) {
+std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::GetSharedBitmapFromId(
+    const gfx::Size&,
+    const SharedBitmapId&) {
   NOTREACHED();
   return nullptr;
 }
 
-std::unique_ptr<cc::SharedBitmap>
+std::unique_ptr<SharedBitmap>
 ClientSharedBitmapManager::GetBitmapForSharedMemory(base::SharedMemory* mem) {
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
-  NotifyAllocatedSharedBitmap(mem, cc::SharedBitmap::GenerateId());
+  SharedBitmapId id = SharedBitmap::GenerateId();
+  NotifyAllocatedSharedBitmap(mem, SharedBitmap::GenerateId());
   return base::MakeUnique<ClientSharedBitmap>(
       shared_bitmap_allocation_notifier_, mem, id);
 }
@@ -160,7 +160,7 @@
 // allocated. Caller keeps ownership of |memory|.
 void ClientSharedBitmapManager::NotifyAllocatedSharedBitmap(
     base::SharedMemory* memory,
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   base::SharedMemoryHandle handle_to_send =
       base::SharedMemory::DuplicateHandle(memory->handle());
   if (!base::SharedMemory::IsHandleValid(handle_to_send)) {
diff --git a/components/viz/client/client_shared_bitmap_manager.h b/components/viz/client/client_shared_bitmap_manager.h
index 5e4154cc..095c535 100644
--- a/components/viz/client/client_shared_bitmap_manager.h
+++ b/components/viz/client/client_shared_bitmap_manager.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
 #include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
 
 namespace viz {
@@ -21,7 +21,7 @@
 // A SharedBitmapManager implementation for use outside of the display
 // compositor's process. This implementation supports SharedBitmaps that
 // can be transported over process boundaries to the display compositor.
-class ClientSharedBitmapManager : public cc::SharedBitmapManager {
+class ClientSharedBitmapManager : public SharedBitmapManager {
  public:
   explicit ClientSharedBitmapManager(
       scoped_refptr<
@@ -29,19 +29,19 @@
           shared_bitmap_allocation_notifier);
   ~ClientSharedBitmapManager() override;
 
-  // cc::SharedBitmapManager implementation.
-  std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+  // SharedBitmapManager implementation.
+  std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
       const gfx::Size& size) override;
-  std::unique_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
+  std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
       const gfx::Size&,
-      const cc::SharedBitmapId&) override;
+      const SharedBitmapId&) override;
 
-  std::unique_ptr<cc::SharedBitmap> GetBitmapForSharedMemory(
+  std::unique_ptr<SharedBitmap> GetBitmapForSharedMemory(
       base::SharedMemory* mem);
 
  private:
   void NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
-                                   const cc::SharedBitmapId& id);
+                                   const SharedBitmapId& id);
 
   scoped_refptr<
       cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index f60c6674..1737f83f 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -13,9 +13,16 @@
     "gl_helper_scaling.cc",
     "gl_helper_scaling.h",
     "quads/resource_format.h",
+    "quads/shared_bitmap.cc",
+    "quads/shared_bitmap.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",
+    "resources/shared_bitmap_manager.h",
   ]
 
   deps = [
@@ -31,20 +38,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/resources/shared_bitmap.cc b/components/viz/common/quads/shared_bitmap.cc
similarity index 93%
rename from cc/resources/shared_bitmap.cc
rename to components/viz/common/quads/shared_bitmap.cc
index c863995c..9f78ee18 100644
--- a/cc/resources/shared_bitmap.cc
+++ b/components/viz/common/quads/shared_bitmap.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -14,13 +14,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 
-namespace cc {
+namespace viz {
 
 SharedBitmap::SharedBitmap(uint8_t* pixels, const SharedBitmapId& id)
     : pixels_(pixels), id_(id) {}
 
-SharedBitmap::~SharedBitmap() {
-}
+SharedBitmap::~SharedBitmap() {}
 
 // static
 bool SharedBitmap::SizeInBytes(const gfx::Size& size, size_t* size_in_bytes) {
@@ -78,4 +77,4 @@
       base::StringPrintf("sharedbitmap-x-process/%s", bitmap_id_hex.c_str()));
 }
 
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/resources/shared_bitmap.h b/components/viz/common/quads/shared_bitmap.h
similarity index 83%
rename from cc/resources/shared_bitmap.h
rename to components/viz/common/quads/shared_bitmap.h
index 6a67cf8..9eb1d977 100644
--- a/cc/resources/shared_bitmap.h
+++ b/components/viz/common/quads/shared_bitmap.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_RESOURCES_SHARED_BITMAP_H_
-#define CC_RESOURCES_SHARED_BITMAP_H_
+#ifndef COMPONENTS_VIZ_COMMON_QUADS_SHARED_BITMAP_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_SHARED_BITMAP_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -11,7 +11,6 @@
 #include "base/hash.h"
 #include "base/macros.h"
 #include "base/trace_event/memory_allocator_dump.h"
-#include "cc/cc_export.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -19,7 +18,7 @@
 class SharedMemoryHandle;
 }
 
-namespace cc {
+namespace viz {
 using SharedBitmapId = gpu::Mailbox;
 
 struct SharedBitmapIdHash {
@@ -28,10 +27,10 @@
   }
 };
 
-CC_EXPORT base::trace_event::MemoryAllocatorDumpGuid
-GetSharedBitmapGUIDForTracing(const SharedBitmapId& bitmap_id);
+base::trace_event::MemoryAllocatorDumpGuid GetSharedBitmapGUIDForTracing(
+    const SharedBitmapId& bitmap_id);
 
-class CC_EXPORT SharedBitmap {
+class SharedBitmap {
  public:
   SharedBitmap(uint8_t* pixels, const SharedBitmapId& id);
 
@@ -65,6 +64,6 @@
   DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_RESOURCES_SHARED_BITMAP_H_
+#endif  // COMPONENTS_VIZ_COMMON_QUADS_SHARED_BITMAP_H_
diff --git a/components/viz/common/resources/DEPS b/components/viz/common/resources/DEPS
index 90a9806..ce3dad4 100644
--- a/components/viz/common/resources/DEPS
+++ b/components/viz/common/resources/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
+  "+gpu/GLES2",
   "+third_party/khronos/GLES2",
+  "+third_party/skia",
   "+ui/gfx",
 ]
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/cc/resources/shared_bitmap_manager.h b/components/viz/common/resources/shared_bitmap_manager.h
similarity index 65%
rename from cc/resources/shared_bitmap_manager.h
rename to components/viz/common/resources/shared_bitmap_manager.h
index 3257a00..630f0d8 100644
--- a/cc/resources/shared_bitmap_manager.h
+++ b/components/viz/common/resources/shared_bitmap_manager.h
@@ -2,19 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
-#define CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
+#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_MANAGER_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_MANAGER_H_
 
 #include <memory>
 
 #include "base/macros.h"
-#include "cc/cc_export.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace cc {
+namespace viz {
 
-class CC_EXPORT SharedBitmapManager {
+class SharedBitmapManager {
  public:
   SharedBitmapManager() {}
   virtual ~SharedBitmapManager() {}
@@ -29,6 +28,6 @@
   DISALLOW_COPY_AND_ASSIGN(SharedBitmapManager);
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
+#endif  // COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_MANAGER_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..6732389 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"
@@ -57,6 +58,12 @@
 
   void CloseChannel(int32_t client_id) override {}
 
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override {}
+
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request) override {}
+
   void CreateGpuMemoryBuffer(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
@@ -225,7 +232,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 +262,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/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
index 3974284..adb493a 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -34,11 +34,11 @@
 
 namespace {
 
-class ServerSharedBitmap : public cc::SharedBitmap {
+class ServerSharedBitmap : public SharedBitmap {
  public:
   ServerSharedBitmap(uint8_t* pixels,
                      scoped_refptr<BitmapData> bitmap_data,
-                     const cc::SharedBitmapId& id,
+                     const SharedBitmapId& id,
                      ServerSharedBitmapManager* manager)
       : SharedBitmap(pixels, id),
         bitmap_data_(bitmap_data),
@@ -49,7 +49,7 @@
       manager_->FreeSharedMemoryFromMap(id());
   }
 
-  // cc::SharedBitmap:
+  // SharedBitmap:
   base::SharedMemoryHandle GetSharedMemoryHandle() const override {
     if (!bitmap_data_->memory)
       return base::SharedMemoryHandle();
@@ -76,11 +76,11 @@
   return g_shared_memory_manager.Pointer();
 }
 
-std::unique_ptr<cc::SharedBitmap>
-ServerSharedBitmapManager::AllocateSharedBitmap(const gfx::Size& size) {
+std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::AllocateSharedBitmap(
+    const gfx::Size& size) {
   base::AutoLock lock(lock_);
   size_t bitmap_size;
-  if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size))
+  if (!SharedBitmap::SizeInBytes(size, &bitmap_size))
     return nullptr;
 
   scoped_refptr<BitmapData> data(new BitmapData(bitmap_size));
@@ -88,15 +88,15 @@
   // allocate them with new instead.
   data->pixels = std::unique_ptr<uint8_t[]>(new uint8_t[bitmap_size]);
 
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
   handle_map_[id] = data;
   return base::MakeUnique<ServerSharedBitmap>(data->pixels.get(), data, id,
                                               this);
 }
 
-std::unique_ptr<cc::SharedBitmap>
-ServerSharedBitmapManager::GetSharedBitmapFromId(const gfx::Size& size,
-                                                 const cc::SharedBitmapId& id) {
+std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId(
+    const gfx::Size& size,
+    const SharedBitmapId& id) {
   base::AutoLock lock(lock_);
   auto it = handle_map_.find(id);
   if (it == handle_map_.end())
@@ -105,7 +105,7 @@
   BitmapData* data = it->second.get();
 
   size_t bitmap_size;
-  if (!cc::SharedBitmap::SizeInBytes(size, &bitmap_size) ||
+  if (!SharedBitmap::SizeInBytes(size, &bitmap_size) ||
       bitmap_size > data->buffer_size)
     return nullptr;
 
@@ -141,7 +141,7 @@
 
     // Generate a global GUID used to share this allocation with renderer
     // processes.
-    auto guid = cc::GetSharedBitmapGUIDForTracing(bitmap.first);
+    auto guid = GetSharedBitmapGUIDForTracing(bitmap.first);
     base::UnguessableToken shared_memory_guid;
     if (bitmap.second->memory) {
       shared_memory_guid = bitmap.second->memory->handle().GetGUID();
@@ -159,7 +159,7 @@
 bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap(
     size_t buffer_size,
     const base::SharedMemoryHandle& handle,
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   base::AutoLock lock(lock_);
   if (handle_map_.find(id) != handle_map_.end())
     return false;
@@ -172,7 +172,7 @@
 }
 
 void ServerSharedBitmapManager::ChildDeletedSharedBitmap(
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   base::AutoLock lock(lock_);
   handle_map_.erase(id);
 }
@@ -183,7 +183,7 @@
 }
 
 void ServerSharedBitmapManager::FreeSharedMemoryFromMap(
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   base::AutoLock lock(lock_);
   handle_map_.erase(id);
 }
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.h b/components/viz/service/display_embedder/server_shared_bitmap_manager.h
index 5f1bce3..cd801a1 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager.h
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager.h
@@ -8,11 +8,12 @@
 #include <memory>
 #include <unordered_map>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
 #include "base/synchronization/lock.h"
 #include "base/trace_event/memory_dump_provider.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "components/viz/service/viz_service_export.h"
 
 namespace viz {
@@ -25,7 +26,7 @@
 // malloc/free, but can only be used in the same process as the display
 // compositor.
 class VIZ_SERVICE_EXPORT ServerSharedBitmapManager
-    : public cc::SharedBitmapManager,
+    : public NON_EXPORTED_BASE(SharedBitmapManager),
       public base::trace_event::MemoryDumpProvider {
  public:
   ServerSharedBitmapManager();
@@ -33,12 +34,12 @@
 
   static ServerSharedBitmapManager* current();
 
-  // cc::SharedBitmapManager implementation.
-  std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+  // SharedBitmapManager implementation.
+  std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
       const gfx::Size& size) override;
-  std::unique_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
+  std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
       const gfx::Size& size,
-      const cc::SharedBitmapId&) override;
+      const SharedBitmapId&) override;
 
   // base::trace_event::MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
@@ -46,21 +47,21 @@
 
   size_t AllocatedBitmapCount() const;
 
-  void FreeSharedMemoryFromMap(const cc::SharedBitmapId& id);
+  void FreeSharedMemoryFromMap(const SharedBitmapId& id);
 
  private:
   friend class SharedBitmapAllocationNotifierImpl;
 
   bool ChildAllocatedSharedBitmap(size_t buffer_size,
                                   const base::SharedMemoryHandle& handle,
-                                  const cc::SharedBitmapId& id);
-  void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id);
+                                  const SharedBitmapId& id);
+  void ChildDeletedSharedBitmap(const SharedBitmapId& id);
 
   mutable base::Lock lock_;
 
-  std::unordered_map<cc::SharedBitmapId,
+  std::unordered_map<SharedBitmapId,
                      scoped_refptr<BitmapData>,
-                     cc::SharedBitmapIdHash>
+                     SharedBitmapIdHash>
       handle_map_;
 
   DISALLOW_COPY_AND_ASSIGN(ServerSharedBitmapManager);
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
index 1875f0a..0cf729b 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
@@ -28,45 +28,45 @@
 TEST_F(ServerSharedBitmapManagerTest, TestCreate) {
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
-  EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+  EXPECT_TRUE(SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
 
   SharedBitmapAllocationNotifierImpl notifier(manager());
   base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
   notifier.ChildAllocatedSharedBitmap(size_in_bytes, handle, id);
 
-  std::unique_ptr<cc::SharedBitmap> large_bitmap;
+  std::unique_ptr<SharedBitmap> large_bitmap;
   large_bitmap = manager()->GetSharedBitmapFromId(gfx::Size(1024, 1024), id);
   EXPECT_TRUE(large_bitmap.get() == NULL);
 
-  std::unique_ptr<cc::SharedBitmap> very_large_bitmap;
+  std::unique_ptr<SharedBitmap> very_large_bitmap;
   very_large_bitmap =
       manager()->GetSharedBitmapFromId(gfx::Size(1, (1 << 30) | 1), id);
   EXPECT_TRUE(very_large_bitmap.get() == NULL);
 
-  std::unique_ptr<cc::SharedBitmap> negative_size_bitmap;
+  std::unique_ptr<SharedBitmap> negative_size_bitmap;
   negative_size_bitmap =
       manager()->GetSharedBitmapFromId(gfx::Size(-1, 1024), id);
   EXPECT_TRUE(negative_size_bitmap.get() == NULL);
 
-  cc::SharedBitmapId id2 = cc::SharedBitmap::GenerateId();
-  std::unique_ptr<cc::SharedBitmap> invalid_bitmap;
+  SharedBitmapId id2 = SharedBitmap::GenerateId();
+  std::unique_ptr<SharedBitmap> invalid_bitmap;
   invalid_bitmap = manager()->GetSharedBitmapFromId(bitmap_size, id2);
   EXPECT_TRUE(invalid_bitmap.get() == NULL);
 
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+  std::unique_ptr<SharedBitmap> shared_bitmap;
   shared_bitmap = manager()->GetSharedBitmapFromId(bitmap_size, id);
   ASSERT_TRUE(shared_bitmap.get() != NULL);
   EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), 4), 0);
 
-  std::unique_ptr<cc::SharedBitmap> large_bitmap2;
+  std::unique_ptr<SharedBitmap> large_bitmap2;
   large_bitmap2 = manager()->GetSharedBitmapFromId(gfx::Size(1024, 1024), id);
   EXPECT_TRUE(large_bitmap2.get() == NULL);
 
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap2;
+  std::unique_ptr<SharedBitmap> shared_bitmap2;
   shared_bitmap2 = manager()->GetSharedBitmapFromId(bitmap_size, id);
   EXPECT_TRUE(shared_bitmap2->pixels() == shared_bitmap->pixels());
   shared_bitmap2.reset();
@@ -86,14 +86,14 @@
 TEST_F(ServerSharedBitmapManagerTest, ServiceDestroyed) {
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
-  EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+  EXPECT_TRUE(SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
 
   // This outlives the SharedBitmapAllocationNotifier.
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+  std::unique_ptr<SharedBitmap> shared_bitmap;
 
   {
     SharedBitmapAllocationNotifierImpl notifier(manager());
@@ -107,7 +107,7 @@
   }
   EXPECT_EQ(0u, manager()->AllocatedBitmapCount());
 
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap2;
+  std::unique_ptr<SharedBitmap> shared_bitmap2;
   shared_bitmap2 = manager()->GetSharedBitmapFromId(bitmap_size, id);
   EXPECT_FALSE(!!shared_bitmap2);
   EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
@@ -117,11 +117,11 @@
 TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) {
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
-  EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+  EXPECT_TRUE(SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
 
   SharedBitmapAllocationNotifierImpl notifier(manager());
 
@@ -134,7 +134,7 @@
 
   notifier.ChildAllocatedSharedBitmap(size_in_bytes, bitmap2->handle(), id);
 
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+  std::unique_ptr<SharedBitmap> shared_bitmap;
   shared_bitmap = manager()->GetSharedBitmapFromId(bitmap_size, id);
   ASSERT_TRUE(shared_bitmap.get() != NULL);
   EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
@@ -145,19 +145,19 @@
 TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) {
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
-  EXPECT_TRUE(cc::SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
+  EXPECT_TRUE(SharedBitmap::SizeInBytes(bitmap_size, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   auto shared_memory_guid = bitmap->handle().GetGUID();
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
-  cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+  SharedBitmapId id = SharedBitmap::GenerateId();
 
   SharedBitmapAllocationNotifierImpl notifier(manager());
 
   base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
   notifier.ChildAllocatedSharedBitmap(size_in_bytes, handle, id);
 
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+  std::unique_ptr<SharedBitmap> shared_bitmap;
   shared_bitmap = manager()->GetSharedBitmapFromId(gfx::Size(1, 1), id);
   EXPECT_EQ(shared_bitmap->GetSharedMemoryHandle().GetGUID(),
             shared_memory_guid);
diff --git a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
index ea52579d..0c667bd 100644
--- a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
+++ b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
@@ -25,7 +25,7 @@
 
 void SharedBitmapAllocationNotifierImpl::DidAllocateSharedBitmap(
     mojo::ScopedSharedBufferHandle buffer,
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   base::SharedMemoryHandle memory_handle;
   size_t size;
   MojoResult result = mojo::UnwrapSharedMemoryHandle(
@@ -35,7 +35,7 @@
 }
 
 void SharedBitmapAllocationNotifierImpl::DidDeleteSharedBitmap(
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   manager_->ChildDeletedSharedBitmap(id);
   owned_bitmaps_.erase(id);
 }
@@ -43,7 +43,7 @@
 void SharedBitmapAllocationNotifierImpl::ChildAllocatedSharedBitmap(
     size_t buffer_size,
     const base::SharedMemoryHandle& handle,
-    const cc::SharedBitmapId& id) {
+    const SharedBitmapId& id) {
   if (manager_->ChildAllocatedSharedBitmap(buffer_size, handle, id))
     owned_bitmaps_.insert(id);
 }
diff --git a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
index 3c96618..c807b55f 100644
--- a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
+++ b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
@@ -8,7 +8,7 @@
 #include <unordered_set>
 
 #include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "components/viz/service/viz_service_export.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
@@ -27,17 +27,17 @@
 
   // cc::mojom::SharedBitmapAllocationNotifier overrides:
   void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
-                               const cc::SharedBitmapId& id) override;
-  void DidDeleteSharedBitmap(const cc::SharedBitmapId& id) override;
+                               const SharedBitmapId& id) override;
+  void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
 
   void ChildAllocatedSharedBitmap(size_t buffer_size,
                                   const base::SharedMemoryHandle& handle,
-                                  const cc::SharedBitmapId& id);
+                                  const SharedBitmapId& id);
 
  private:
   ServerSharedBitmapManager* const manager_;
   mojo::AssociatedBinding<cc::mojom::SharedBitmapAllocationNotifier> binding_;
-  std::unordered_set<cc::SharedBitmapId, cc::SharedBitmapIdHash> owned_bitmaps_;
+  std::unordered_set<SharedBitmapId, SharedBitmapIdHash> owned_bitmaps_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedBitmapAllocationNotifierImpl);
 };
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/android/dialog_overlay_impl.cc b/content/browser/android/dialog_overlay_impl.cc
index 2077559..8ea7141 100644
--- a/content/browser/android/dialog_overlay_impl.cc
+++ b/content/browser/android/dialog_overlay_impl.cc
@@ -33,24 +33,37 @@
                                      const base::UnguessableToken& token)
     : token_(token), cvc_(nullptr) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  cvc_ = GetContentViewCore();
 
   JNIEnv* env = AttachCurrentThread();
   obj_ = JavaObjectWeakGlobalRef(env, obj);
 
-  // If there's no CVC, then just post a null token immediately.
+  cvc_ = GetContentViewCore();
+  if (cvc_)
+    cvc_->AddObserver(this);
+
+  // Note that we're not allowed to call back into |obj| before it calls
+  // CompleteInit.  However, the observer won't actually call us back until the
+  // token changes.  As long as the java side calls us from the ui thread before
+  // returning, we won't send a callback before then.
+}
+
+void DialogOverlayImpl::CompleteInit(JNIEnv* env,
+                                     const JavaParamRef<jobject>& obj) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // If there's no CVC, then notify our caller.
   if (!cvc_) {
     Java_DialogOverlayImpl_onDismissed(env, obj.obj());
     return;
   }
 
-  cvc_->AddObserver(this);
-
-  // Also send the initial token, since we'll only get changes.
+  // Send the initial token, if there is one.  The observer will notify us about
+  // changes only.
   if (ui::WindowAndroid* window = cvc_->GetWindowAndroid()) {
     ScopedJavaLocalRef<jobject> token = window->GetWindowToken();
     if (!token.is_null())
       Java_DialogOverlayImpl_onWindowToken(env, obj.obj(), token);
+    // else we will send one if we get a callback from |cvc_|.
   }
 }
 
@@ -77,8 +90,8 @@
       point = view->GetLocationOfContainerViewOnScreen();
   }
 
-  Java_DialogOverlayImpl_receiveCompositorOffset(env, obj.obj(), rect.obj(),
-                                                 point.x(), point.y());
+  Java_DialogOverlayImpl_receiveCompositorOffset(env, rect.obj(), point.x(),
+                                                 point.y());
 }
 
 void DialogOverlayImpl::UnregisterForTokensIfNeeded() {
@@ -162,4 +175,13 @@
   gpu::GpuSurfaceTracker::Get()->RemoveSurface(surface_id);
 }
 
+static ScopedJavaLocalRef<jobject> LookupSurfaceForTesting(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& jcaller,
+    jint surfaceId) {
+  gl::ScopedJavaSurface surface =
+      gpu::GpuSurfaceTracker::Get()->AcquireJavaSurface(surfaceId);
+  return ScopedJavaLocalRef<jobject>(surface.j_surface());
+}
+
 }  // namespace content
diff --git a/content/browser/android/dialog_overlay_impl.h b/content/browser/android/dialog_overlay_impl.h
index 32efbbe..82d44e3 100644
--- a/content/browser/android/dialog_overlay_impl.h
+++ b/content/browser/android/dialog_overlay_impl.h
@@ -23,10 +23,18 @@
   // Registers the JNI methods for DialogOverlayImpl.
   static bool RegisterDialogOverlayImpl(JNIEnv* env);
 
+  // This may not call back into |obj| directly, but must post.  This is because
+  // |obj| is still being initialized.
   DialogOverlayImpl(const base::android::JavaParamRef<jobject>& obj,
                     const base::UnguessableToken& token);
   ~DialogOverlayImpl() override;
 
+  // Called when the java side is ready for token / dismissed callbacks.  May
+  // call back before returning.  Must guarantee that a token is eventually sent
+  // if we have one.
+  void CompleteInit(JNIEnv* env,
+                    const base::android::JavaParamRef<jobject>& obj);
+
   // Clean up and post to delete |this| later.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/content/browser/appcache/appcache_group_unittest.cc b/content/browser/appcache/appcache_group_unittest.cc
index 180e522..fbc489dd 100644
--- a/content/browser/appcache/appcache_group_unittest.cc
+++ b/content/browser/appcache/appcache_group_unittest.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_group.h"
 #include "content/browser/appcache/appcache_host.h"
@@ -95,7 +95,7 @@
 
 class AppCacheGroupTest : public testing::Test {
  private:
-  base::MessageLoop message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 TEST_F(AppCacheGroupTest, AddRemoveCache) {
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc
index 221afb21..16c3626 100644
--- a/content/browser/appcache/appcache_host_unittest.cc
+++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -10,7 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_group.h"
@@ -148,7 +148,7 @@
     last_callback_param_ = param;
   }
 
-  base::MessageLoop message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   // Mock classes for the 'host' to work with
   MockAppCacheService service_;
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index 02c104a..94ec32f2 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -18,10 +18,10 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
@@ -179,13 +179,15 @@
   };
 
   static void SetUpTestCase() {
+    scoped_task_environment_.reset(new base::test::ScopedTaskEnvironment);
     io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     io_thread_->StartWithOptions(options);
   }
 
   static void TearDownTestCase() {
-    io_thread_.reset(NULL);
+    io_thread_.reset();
+    scoped_task_environment_.reset();
   }
 
   // Test harness --------------------------------------------------
@@ -1085,10 +1087,14 @@
   std::unique_ptr<AppCacheURLRequestJob> job_;
 
   static std::unique_ptr<base::Thread> io_thread_;
+  static std::unique_ptr<base::test::ScopedTaskEnvironment>
+      scoped_task_environment_;
 };
 
 // static
 std::unique_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_;
+std::unique_ptr<base::test::ScopedTaskEnvironment>
+    AppCacheRequestHandlerTest::scoped_task_environment_;
 
 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
   RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
diff --git a/content/browser/appcache/appcache_response_unittest.cc b/content/browser/appcache/appcache_response_unittest.cc
index 3fd5f1c..34ed2c41 100644
--- a/content/browser/appcache/appcache_response_unittest.cc
+++ b/content/browser/appcache/appcache_response_unittest.cc
@@ -15,10 +15,10 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/pickle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_response.h"
@@ -69,13 +69,15 @@
   }
 
   static void SetUpTestCase() {
+    scoped_task_environment_.reset(new base::test::ScopedTaskEnvironment);
     io_thread_.reset(new base::Thread("AppCacheResponseTest Thread"));
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     io_thread_->StartWithOptions(options);
   }
 
   static void TearDownTestCase() {
-    io_thread_.reset(NULL);
+    io_thread_.reset();
+    scoped_task_environment_.reset();
   }
 
   AppCacheResponseTest() {}
@@ -784,10 +786,14 @@
   bool write_callback_was_called_;
 
   static std::unique_ptr<base::Thread> io_thread_;
+  static std::unique_ptr<base::test::ScopedTaskEnvironment>
+      scoped_task_environment_;
 };
 
 // static
 std::unique_ptr<base::Thread> AppCacheResponseTest::io_thread_;
+std::unique_ptr<base::test::ScopedTaskEnvironment>
+    AppCacheResponseTest::scoped_task_environment_;
 
 TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
   RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index 2978f499..9af861b 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -14,7 +14,8 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_entry.h"
@@ -68,7 +69,7 @@
   void CallCallback(int rv) {
     if (!callback_.is_null()) {
       // Defer to guarantee async completion.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      base::SequencedTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(&DeferredCallback, callback_, rv));
     }
     callback_.Reset();
@@ -399,7 +400,10 @@
 
 AppCacheServiceImpl::AppCacheServiceImpl(
     storage::QuotaManagerProxy* quota_manager_proxy)
-    : appcache_policy_(nullptr),
+    : db_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+           base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
+      appcache_policy_(nullptr),
       quota_client_(nullptr),
       handler_factory_(nullptr),
       quota_manager_proxy_(quota_manager_proxy),
@@ -429,14 +433,12 @@
 
 void AppCacheServiceImpl::Initialize(
     const base::FilePath& cache_directory,
-    const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
     const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread) {
   DCHECK(!storage_.get());
   cache_directory_ = cache_directory;
-  db_thread_ = db_thread;
   cache_thread_ = cache_thread;
   AppCacheStorageImpl* storage = new AppCacheStorageImpl(this);
-  storage->Initialize(cache_directory, db_thread, cache_thread);
+  storage->Initialize(cache_directory, db_task_runner_, cache_thread);
   storage_.reset(storage);
 }
 
@@ -478,7 +480,7 @@
   for (auto& observer : observers_)
     observer.OnServiceReinitialized(old_storage_ref.get());
 
-  Initialize(cache_directory_, db_thread_, cache_thread_);
+  Initialize(cache_directory_, cache_thread_);
 }
 
 void AppCacheServiceImpl::GetAllAppCacheInfo(
diff --git a/content/browser/appcache/appcache_service_impl.h b/content/browser/appcache/appcache_service_impl.h
index ea78f69..372e96e8 100644
--- a/content/browser/appcache/appcache_service_impl.h
+++ b/content/browser/appcache/appcache_service_impl.h
@@ -50,9 +50,10 @@
 // during Reinitialization.
 class CONTENT_EXPORT AppCacheStorageReference
     : public base::RefCounted<AppCacheStorageReference> {
-public:
+ public:
   AppCacheStorage* storage() const { return storage_.get(); }
-private:
+
+ private:
   friend class AppCacheServiceImpl;
   friend class base::RefCounted<AppCacheStorageReference>;
   AppCacheStorageReference(std::unique_ptr<AppCacheStorage> storage);
@@ -88,7 +89,6 @@
 
   void Initialize(
       const base::FilePath& cache_directory,
-      const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
       const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread);
 
   void AddObserver(Observer* observer) {
@@ -201,7 +201,7 @@
   void Reinitialize();
 
   base::FilePath cache_directory_;
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+  scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
   AppCachePolicy* appcache_policy_;
   AppCacheQuotaClient* quota_client_;
diff --git a/content/browser/appcache/appcache_service_unittest.cc b/content/browser/appcache/appcache_service_unittest.cc
index 0f1c7f02..552244a 100644
--- a/content/browser/appcache/appcache_service_unittest.cc
+++ b/content/browser/appcache/appcache_service_unittest.cc
@@ -183,13 +183,11 @@
   const GURL kOrigin;
   const GURL kManifestUrl;
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<AppCacheServiceImpl> service_;
   int delete_result_;
   int delete_completion_count_;
   net::CompletionCallback deletion_callback_;
-
- private:
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 0307853..6e8dac79 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -21,7 +21,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_database.h"
@@ -144,7 +144,7 @@
   explicit DatabaseTask(AppCacheStorageImpl* storage)
       : storage_(storage),
         database_(storage->database_),
-        io_thread_(base::ThreadTaskRunnerHandle::Get()) {
+        io_thread_(base::SequencedTaskRunnerHandle::Get()) {
     DCHECK(io_thread_.get());
   }
 
@@ -185,16 +185,16 @@
   void CallRunCompleted(base::TimeTicks schedule_time);
   void OnFatalError();
 
-  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
+  scoped_refptr<base::SequencedTaskRunner> io_thread_;
 };
 
 void AppCacheStorageImpl::DatabaseTask::Schedule() {
   DCHECK(storage_);
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_->RunsTasksInCurrentSequence());
   if (!storage_->database_)
     return;
 
-  if (storage_->db_thread_->PostTask(
+  if (storage_->db_task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&DatabaseTask::CallRun, this, base::TimeTicks::Now()))) {
     storage_->scheduled_database_tasks_.push_back(this);
@@ -204,7 +204,7 @@
 }
 
 void AppCacheStorageImpl::DatabaseTask::CancelCompletion() {
-  DCHECK(io_thread_->BelongsToCurrentThread());
+  DCHECK(io_thread_->RunsTasksInCurrentSequence());
   delegates_.clear();
   storage_ = NULL;
 }
@@ -240,7 +240,7 @@
   AppCacheHistograms::AddCompletionQueueTimeSample(
       base::TimeTicks::Now() - schedule_time);
   if (storage_) {
-    DCHECK(io_thread_->BelongsToCurrentThread());
+    DCHECK(io_thread_->RunsTasksInCurrentSequence());
     DCHECK(storage_->scheduled_database_tasks_.front() == this);
     storage_->scheduled_database_tasks_.pop_front();
     base::TimeTicks run_time = base::TimeTicks::Now();
@@ -253,7 +253,7 @@
 
 void AppCacheStorageImpl::DatabaseTask::OnFatalError() {
   if (storage_) {
-    DCHECK(io_thread_->BelongsToCurrentThread());
+    DCHECK(io_thread_->RunsTasksInCurrentSequence());
     storage_->Disable();
     storage_->DeleteAndStartOver();
   }
@@ -321,7 +321,7 @@
   if (!storage_->is_disabled()) {
     storage_->usage_map_.swap(usage_map_);
     const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&AppCacheStorageImpl::DelayedStartDeletingUnusedResponses,
                    storage_->weak_factory_.GetWeakPtr()),
@@ -1425,10 +1425,9 @@
     task->CancelCompletion();
 
   if (database_ &&
-      !db_thread_->PostTask(
+      !db_task_runner_->PostTask(
           FROM_HERE,
-          base::Bind(&ClearSessionOnlyOrigins,
-                     database_,
+          base::Bind(&ClearSessionOnlyOrigins, database_,
                      make_scoped_refptr(service_->special_storage_policy()),
                      service()->force_keep_session_state()))) {
     delete database_;
@@ -1438,10 +1437,8 @@
 
 void AppCacheStorageImpl::Initialize(
     const base::FilePath& cache_directory,
-    const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+    const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
     const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread) {
-  DCHECK(db_thread.get());
-
   cache_directory_ = cache_directory;
   is_incognito_ = cache_directory_.empty();
 
@@ -1450,7 +1447,7 @@
     db_file_path = cache_directory_.Append(kAppCacheDatabaseName);
   database_ = new AppCacheDatabase(db_file_path);
 
-  db_thread_ = db_thread;
+  db_task_runner_ = db_task_runner;
   cache_thread_ = cache_thread;
 
   scoped_refptr<InitTask> task(new InitTask(this));
@@ -1806,9 +1803,10 @@
 void AppCacheStorageImpl::ScheduleDeleteOneResponse() {
   DCHECK(!is_response_deletion_scheduled_);
   const base::TimeDelta kBriefDelay = base::TimeDelta::FromMilliseconds(10);
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
-                            weak_factory_.GetWeakPtr()),
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
+                 weak_factory_.GetWeakPtr()),
       kBriefDelay);
   is_response_deletion_scheduled_ = true;
 }
@@ -1891,7 +1889,7 @@
 
 void AppCacheStorageImpl::ScheduleSimpleTask(const base::Closure& task) {
   pending_simple_tasks_.push_back(task);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&AppCacheStorageImpl::RunOnePendingSimpleTask,
                             weak_factory_.GetWeakPtr()));
 }
@@ -1961,7 +1959,7 @@
 }
 
 void AppCacheStorageImpl::DeleteAndStartOverPart2() {
-  db_thread_->PostTaskAndReply(
+  db_task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&base::DeleteFile), cache_directory_, true),
       base::Bind(&AppCacheStorageImpl::CallScheduleReinitialize,
diff --git a/content/browser/appcache/appcache_storage_impl.h b/content/browser/appcache/appcache_storage_impl.h
index 067b3e6..cde701e1 100644
--- a/content/browser/appcache/appcache_storage_impl.h
+++ b/content/browser/appcache/appcache_storage_impl.h
@@ -38,7 +38,7 @@
 
   void Initialize(
       const base::FilePath& cache_directory,
-      const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+      const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
       const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread);
   void Disable();
   bool is_disabled() const { return is_disabled_; }
@@ -156,7 +156,7 @@
   // This class operates primarily on the IO thread, but schedules
   // its DatabaseTasks on the db thread. Separately, the disk_cache uses
   // the cache thread.
-  scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+  scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
 
   // Structures to keep track of DatabaseTasks that are in-flight.
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 3ccba135..4752d8f 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -21,8 +21,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_database.h"
@@ -187,8 +188,9 @@
   std::unique_ptr<net::URLRequestContext> request_context_;
 };
 
+std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment;
 std::unique_ptr<IOThread> io_thread;
-std::unique_ptr<base::Thread> db_thread;
+std::unique_ptr<base::Thread> background_thread;
 
 }  // namespace
 
@@ -278,7 +280,7 @@
         : QuotaManager(true /* is_incognito */,
                        base::FilePath(),
                        io_thread->task_runner().get(),
-                       db_thread->task_runner().get(),
+                       background_thread->task_runner().get(),
                        nullptr,
                        storage::GetQuotaSettingsFunc()),
           async_(false) {}
@@ -288,7 +290,7 @@
                           const UsageAndQuotaCallback& callback) override {
       EXPECT_EQ(storage::kStorageTypeTemporary, type);
       if (async_) {
-        base::ThreadTaskRunnerHandle::Get()->PostTask(
+        base::SequencedTaskRunnerHandle::Get()->PostTask(
             FROM_HERE, base::Bind(&MockQuotaManager::CallCallback,
                                   base::Unretained(this), callback));
         return;
@@ -372,29 +374,32 @@
     SetUpTest();
 
     // Ensure InitTask execution prior to conducting a test.
-    FlushDbThreadTasks();
+    FlushAllTasks();
 
     // We also have to wait for InitTask completion call to be performed
     // on the IO thread prior to running the test. Its guaranteed to be
     // queued by this time.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
                               base::Unretained(this), method));
   }
 
   static void SetUpTestCase() {
+    scoped_task_environment.reset(new base::test::ScopedTaskEnvironment());
+
     // We start both threads as TYPE_IO because we also use the db_thead
     // for the disk_cache which needs to be of TYPE_IO.
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     io_thread.reset(new IOThread("AppCacheTest.IOThread"));
     ASSERT_TRUE(io_thread->StartWithOptions(options));
-    db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
-    ASSERT_TRUE(db_thread->StartWithOptions(options));
+    background_thread.reset(new base::Thread("AppCacheTest::BackgroundThread"));
+    ASSERT_TRUE(background_thread->StartWithOptions(options));
   }
 
   static void TearDownTestCase() {
-    io_thread.reset(NULL);
-    db_thread.reset(NULL);
+    io_thread.reset();
+    background_thread.reset();
+    scoped_task_environment.reset();
   }
 
   // Test harness --------------------------------------------------
@@ -414,8 +419,8 @@
 
   void SetUpTest() {
     DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
-    service_.reset(new AppCacheServiceImpl(NULL));
-    service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL);
+    service_.reset(new AppCacheServiceImpl(nullptr));
+    service_->Initialize(base::FilePath(), background_thread->task_runner());
     mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
     service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
     delegate_.reset(new MockStorageDelegate(this));
@@ -423,6 +428,8 @@
 
   void TearDownTest() {
     DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
+    scoped_refptr<base::SequencedTaskRunner> db_runner =
+        storage()->db_task_runner_;
     storage()->CancelDelegateCallbacks(delegate());
     group_ = NULL;
     cache_ = NULL;
@@ -430,14 +437,16 @@
     mock_quota_manager_proxy_ = NULL;
     delegate_.reset();
     service_.reset();
-    FlushDbThreadTasks();
+    FlushTasks(db_runner.get());
+    FlushTasks(background_thread->task_runner().get());
+    FlushTasks(db_runner.get());
   }
 
   void TestFinished() {
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
     DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
                               base::Unretained(this)));
   }
@@ -456,7 +465,8 @@
     if (task_stack_.empty()) {
       return;
     }
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_stack_.top());
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     task_stack_.top());
     task_stack_.pop();
   }
 
@@ -464,13 +474,19 @@
     event->Signal();
   }
 
-  void FlushDbThreadTasks() {
+  void FlushAllTasks() {
+    FlushTasks(storage()->db_task_runner_.get());
+    FlushTasks(background_thread->task_runner().get());
+    FlushTasks(storage()->db_task_runner_.get());
+  }
+
+  void FlushTasks(base::SequencedTaskRunner* runner) {
     // We pump a task thru the db thread to ensure any tasks previously
     // scheduled on that thread have been performed prior to return.
     base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                               base::WaitableEvent::InitialState::NOT_SIGNALED);
-    db_thread->task_runner()->PostTask(
-        FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
+    runner->PostTask(FROM_HERE,
+                     base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
     event.Wait();
   }
 
@@ -899,7 +915,7 @@
 
     // And the entry in storage should also be updated, but that
     // happens asynchronously on the db thread.
-    FlushDbThreadTasks();
+    FlushAllTasks();
     AppCacheDatabase::EntryRecord entry_record2;
     EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
     EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
@@ -944,7 +960,7 @@
     EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
 
     // And the entry in storage should also be updated.
-    FlushDbThreadTasks();
+    FlushAllTasks();
     AppCacheDatabase::EntryRecord entry_record;
     EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
     EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
@@ -1724,8 +1740,8 @@
     // Recreate the service to point at the db and corruption on disk.
     service_.reset(new AppCacheServiceImpl(NULL));
     service_->set_request_context(io_thread->request_context());
-    service_->Initialize(temp_directory_.GetPath(), db_thread->task_runner(),
-                         db_thread->task_runner());
+    service_->Initialize(temp_directory_.GetPath(),
+                         background_thread->task_runner());
     mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
     service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
     delegate_.reset(new MockStorageDelegate(this));
@@ -1736,8 +1752,8 @@
 
     // We continue after the init task is complete including the callback
     // on the current thread.
-    FlushDbThreadTasks();
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    FlushAllTasks();
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
                               base::Unretained(this), test_case));
   }
@@ -1814,7 +1830,6 @@
     } else {
       ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
       AppCacheHost* host2 = backend_->GetHost(2);
-      EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
       EXPECT_TRUE(host2->disabled_storage_reference_.get());
     }
 
diff --git a/content/browser/appcache/appcache_storage_unittest.cc b/content/browser/appcache/appcache_storage_unittest.cc
index 857728f..ab582aa7 100644
--- a/content/browser/appcache/appcache_storage_unittest.cc
+++ b/content/browser/appcache/appcache_storage_unittest.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "content/browser/appcache/appcache_storage.h"
-#include "base/message_loop/message_loop.h"
+
+#include "base/test/scoped_task_environment.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_group.h"
 #include "content/browser/appcache/appcache_response.h"
@@ -22,6 +23,9 @@
   class MockStorageDelegate : public AppCacheStorage::Delegate {
    public:
   };
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 TEST_F(AppCacheStorageTest, AddRemoveCache) {
diff --git a/content/browser/appcache/appcache_unittest.cc b/content/browser/appcache/appcache_unittest.cc
index 42bf790..33496ca2 100644
--- a/content/browser/appcache/appcache_unittest.cc
+++ b/content/browser/appcache/appcache_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/test/scoped_task_environment.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_host.h"
 #include "content/browser/appcache/mock_appcache_service.h"
@@ -36,9 +37,10 @@
 }  // namespace
 
 class AppCacheTest : public testing::Test {
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
-TEST(AppCacheTest, CleanupUnusedCache) {
+TEST_F(AppCacheTest, CleanupUnusedCache) {
   MockAppCacheService service;
   MockAppCacheFrontend frontend;
   scoped_refptr<AppCache> cache(new AppCache(service.storage(), 111));
@@ -57,7 +59,7 @@
   host2.AssociateNoCache(GURL());
 }
 
-TEST(AppCacheTest, AddModifyRemoveEntry) {
+TEST_F(AppCacheTest, AddModifyRemoveEntry) {
   MockAppCacheService service;
   scoped_refptr<AppCache> cache(new AppCache(service.storage(), 111));
 
@@ -101,7 +103,7 @@
   EXPECT_TRUE(cache->entries().empty());
 }
 
-TEST(AppCacheTest, InitializeWithManifest) {
+TEST_F(AppCacheTest, InitializeWithManifest) {
   MockAppCacheService service;
 
   scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
@@ -145,7 +147,7 @@
   EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
 }
 
-TEST(AppCacheTest, FindResponseForRequest) {
+TEST_F(AppCacheTest, FindResponseForRequest) {
   MockAppCacheService service;
 
   const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
@@ -357,7 +359,7 @@
   EXPECT_FALSE(network_namespace);
 }
 
-TEST(AppCacheTest, FindInterceptPatternResponseForRequest) {
+TEST_F(AppCacheTest, FindInterceptPatternResponseForRequest) {
   MockAppCacheService service;
 
   // Setup an appcache with an intercept namespace that uses pattern matching.
@@ -428,7 +430,7 @@
   EXPECT_FALSE(network_namespace);
 }
 
-TEST(AppCacheTest, FindFallbackPatternResponseForRequest) {
+TEST_F(AppCacheTest, FindFallbackPatternResponseForRequest) {
   MockAppCacheService service;
 
   // Setup an appcache with a fallback namespace that uses pattern matching.
@@ -499,8 +501,7 @@
   EXPECT_FALSE(network_namespace);
 }
 
-
-TEST(AppCacheTest, FindNetworkNamespacePatternResponseForRequest) {
+TEST_F(AppCacheTest, FindNetworkNamespacePatternResponseForRequest) {
   MockAppCacheService service;
 
   // Setup an appcache with a network namespace that uses pattern matching.
@@ -542,7 +543,7 @@
   EXPECT_FALSE(fallback_entry.has_response_id());
 }
 
-TEST(AppCacheTest, ToFromDatabaseRecords) {
+TEST_F(AppCacheTest, ToFromDatabaseRecords) {
   // Setup a cache with some entries.
   const int64_t kCacheId = 1234;
   const int64_t kGroupId = 4321;
@@ -627,7 +628,7 @@
             cache->online_whitelist_namespaces_[0].namespace_url);
 }
 
-TEST(AppCacheTest, IsNamespaceMatch) {
+TEST_F(AppCacheTest, IsNamespaceMatch) {
   AppCacheNamespace prefix;
   prefix.namespace_url = GURL("http://foo.com/prefix");
   prefix.is_pattern = false;
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index bf3752e..078a640 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -14,11 +14,11 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_group.h"
@@ -3415,6 +3415,7 @@
     MANIFEST_WITH_INTERCEPT
   };
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<IOThread> io_thread_;
 
   std::unique_ptr<MockAppCacheService> service_;
diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc
index 1a75b97..ed8b6e91 100644
--- a/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -19,10 +19,10 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/pickle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_response.h"
@@ -230,13 +230,15 @@
   }
 
   static void SetUpTestCase() {
+    scoped_task_environment_.reset(new base::test::ScopedTaskEnvironment());
     io_thread_.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     io_thread_->StartWithOptions(options);
   }
 
   static void TearDownTestCase() {
-    io_thread_.reset(NULL);
+    io_thread_.reset();
+    scoped_task_environment_.reset();
   }
 
   AppCacheURLRequestJobTest() {}
@@ -864,10 +866,14 @@
   std::unique_ptr<MockURLRequestDelegate> url_request_delegate_;
 
   static std::unique_ptr<base::Thread> io_thread_;
+  static std::unique_ptr<base::test::ScopedTaskEnvironment>
+      scoped_task_environment_;
 };
 
 // static
 std::unique_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_;
+std::unique_ptr<base::test::ScopedTaskEnvironment>
+    AppCacheURLRequestJobTest::scoped_task_environment_;
 
 TEST_F(AppCacheURLRequestJobTest, Basic) {
   RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic);
diff --git a/content/browser/appcache/chrome_appcache_service.cc b/content/browser/appcache/chrome_appcache_service.cc
index a508c5e..cdceb0a 100644
--- a/content/browser/appcache/chrome_appcache_service.cc
+++ b/content/browser/appcache/chrome_appcache_service.cc
@@ -44,9 +44,7 @@
     set_request_context(request_context_getter->GetURLRequestContext());
 
   // Init our base class.
-  Initialize(cache_path_, BrowserThread::GetTaskRunnerForThread(
-                              BrowserThread::FILE_USER_BLOCKING)
-                              .get(),
+  Initialize(cache_path_,
              BrowserThread::GetTaskRunnerForThread(BrowserThread::CACHE).get());
   set_appcache_policy(this);
   set_special_storage_policy(special_storage_policy.get());
diff --git a/content/browser/appcache/chrome_appcache_service_unittest.cc b/content/browser/appcache/chrome_appcache_service_unittest.cc
index 7a66a2a7..c69ce704 100644
--- a/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_database.h"
 #include "content/browser/appcache/appcache_storage_impl.h"
@@ -64,7 +65,9 @@
 class ChromeAppCacheServiceTest : public testing::Test {
  public:
   ChromeAppCacheServiceTest()
-      : kProtectedManifestURL(kProtectedManifest),
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO),
+        kProtectedManifestURL(kProtectedManifest),
         kNormalManifestURL(kNormalManifest),
         kSessionOnlyManifestURL(kSessionOnlyManifest),
         thread_bundle_(TestBrowserThreadBundle::Options::IO_MAINLOOP) {}
@@ -75,6 +78,7 @@
       bool init_storage);
   void InsertDataIntoAppCache(ChromeAppCacheService* appcache_service);
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   base::ScopedTempDir temp_dir_;
   const GURL kProtectedManifestURL;
   const GURL kNormalManifestURL;
@@ -106,14 +110,14 @@
                  browser_context_.GetResourceContext(),
                  base::RetainedRef(mock_request_context_getter), mock_policy));
   // Steps needed to initialize the storage of AppCache data.
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
   if (init_storage) {
     AppCacheStorageImpl* storage =
         static_cast<AppCacheStorageImpl*>(
             appcache_service->storage());
     storage->database_->db_connection();
     storage->disk_cache();
-    base::RunLoop().RunUntilIdle();
+    scoped_task_environment_.RunUntilIdle();
   }
   return appcache_service;
 }
@@ -149,7 +153,7 @@
 
   // Test: delete the ChromeAppCacheService
   appcache_service = NULL;
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 
   // Recreate the appcache (for reading the data back)
   appcache_service = CreateAppCacheServiceImpl(appcache_path, false);
@@ -169,7 +173,7 @@
 
   // Delete and let cleanup tasks run prior to returning.
   appcache_service = NULL;
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 }
 
 TEST_F(ChromeAppCacheServiceTest, SaveSessionState) {
@@ -189,7 +193,7 @@
 
   // Test: delete the ChromeAppCacheService
   appcache_service = NULL;
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 
   // Recreate the appcache (for reading the data back)
   appcache_service = CreateAppCacheServiceImpl(appcache_path, false);
@@ -209,7 +213,7 @@
 
   // Delete and let cleanup tasks run prior to returning.
   appcache_service = NULL;
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 }
 
 }  // namespace content
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index be8eddc..2db01e75 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1475,12 +1475,6 @@
 #endif  // defined(USE_AURA)
 #endif  // defined(OS_ANDROID)
 
-  // Enable the GpuMemoryBuffer dump provider with IO thread affinity. Note that
-  // unregistration happens on the IO thread (See
-  // BrowserProcessSubThread::IOThreadPreCleanUp).
-  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      BrowserGpuMemoryBufferManager::current(), "BrowserGpuMemoryBufferManager",
-      io_thread_->task_runner());
 #if defined(OS_ANDROID)
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics",
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 19b47d9..2224f98 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -41,7 +41,6 @@
 #include "content/browser/compositor/offscreen_browser_compositor_output_surface.h"
 #include "content/browser/compositor/reflector_impl.h"
 #include "content/browser/compositor/software_browser_compositor_output_surface.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -812,7 +811,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/compositor/software_output_device_win.cc b/content/browser/compositor/software_output_device_win.cc
index 4261878..e1a9968 100644
--- a/content/browser/compositor/software_output_device_win.cc
+++ b/content/browser/compositor/software_output_device_win.cc
@@ -6,7 +6,7 @@
 
 #include "base/debug/alias.h"
 #include "base/memory/shared_memory.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "content/public/browser/browser_thread.h"
 #include "skia/ext/platform_canvas.h"
 #include "skia/ext/skia_utils_win.h"
@@ -58,7 +58,7 @@
     return backing_.get();
   size_t expected_byte_size = GetMaxByteSize();
   size_t required_size;
-  if (!cc::SharedBitmap::SizeInBytes(size, &required_size))
+  if (!viz::SharedBitmap::SizeInBytes(size, &required_size))
     return nullptr;
   if (required_size > expected_byte_size)
     return nullptr;
@@ -76,8 +76,8 @@
   size_t max_size = 1;
   for (const SoftwareOutputDeviceWin* device : devices_) {
     size_t current_size;
-    if (!cc::SharedBitmap::SizeInBytes(device->viewport_pixel_size(),
-                                       &current_size))
+    if (!viz::SharedBitmap::SizeInBytes(device->viewport_pixel_size(),
+                                        &current_size))
       continue;
     if (current_size > kMaxBitmapSizeBytes)
       continue;
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 f15af73e..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 df0c3eda..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/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index 9331063..bd0afaa 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -71,6 +72,14 @@
       gpu_client_tracing_id_(gpu_client_tracing_id) {
   DCHECK(!g_gpu_memory_buffer_manager);
   g_gpu_memory_buffer_manager = this;
+
+  // Enable the dump provider with IO thread affinity. Note that
+  // unregistration happens on the IO thread (See
+  // BrowserProcessSubThread::IOThreadPreCleanUp).
+  DCHECK(BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
+  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "BrowserGpuMemoryBufferManager",
+      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
 }
 
 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index a51635a..04615566 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -19,7 +19,6 @@
 #include "build/build_config.h"
 #include "cc/base/math_util.h"
 #include "cc/base/switches.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/public/browser/gpu_utils.h"
 #include "content/public/common/content_features.h"
@@ -402,8 +401,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/gpu/gpu_client.cc b/content/browser/gpu/gpu_client.cc
index 38079ec9..ccb775f 100644
--- a/content/browser/gpu/gpu_client.cc
+++ b/content/browser/gpu/gpu_client.cc
@@ -76,6 +76,20 @@
                  callback));
 }
 
+void GpuClient::CreateJpegDecodeAccelerator(
+    media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
+  GpuProcessHost* host = GpuProcessHost::Get();
+  if (host)
+    host->gpu_service()->CreateJpegDecodeAccelerator(std::move(jda_request));
+}
+
+void GpuClient::CreateVideoEncodeAccelerator(
+    media::mojom::VideoEncodeAcceleratorRequest vea_request) {
+  GpuProcessHost* host = GpuProcessHost::Get();
+  if (host)
+    host->gpu_service()->CreateVideoEncodeAccelerator(std::move(vea_request));
+}
+
 void GpuClient::CreateGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     const gfx::Size& size,
diff --git a/content/browser/gpu/gpu_client.h b/content/browser/gpu/gpu_client.h
index 4e45d860..db213b22 100644
--- a/content/browser/gpu/gpu_client.h
+++ b/content/browser/gpu/gpu_client.h
@@ -32,6 +32,10 @@
   // ui::mojom::Gpu overrides:
   void EstablishGpuChannel(
       const EstablishGpuChannelCallback& callback) override;
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override;
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request) override;
   void CreateGpuMemoryBuffer(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index a982ead9f..622a11b 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -17,13 +17,13 @@
 #include "base/i18n/time_formatting.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringize_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/grit/content_resources.h"
@@ -38,6 +38,7 @@
 #include "content/public/common/url_constants.h"
 #include "gpu/config/gpu_feature_type.h"
 #include "gpu/config/gpu_info.h"
+#include "gpu/ipc/host/gpu_memory_buffer_support.h"
 #include "skia/ext/skia_commit_hash.h"
 #include "third_party/angle/src/common/version.h"
 #include "third_party/skia/include/core/SkMilestone.h"
@@ -334,21 +335,22 @@
 std::unique_ptr<base::ListValue> GpuMemoryBufferInfo() {
   auto gpu_memory_buffer_info = base::MakeUnique<base::ListValue>();
 
-  BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
-      BrowserGpuMemoryBufferManager::current();
-
+  const auto native_configurations =
+      gpu::GetNativeGpuMemoryBufferConfigurations();
   for (size_t format = 0;
        format < static_cast<size_t>(gfx::BufferFormat::LAST) + 1; format++) {
     std::string native_usage_support;
     for (size_t usage = 0;
          usage < static_cast<size_t>(gfx::BufferUsage::LAST) + 1; usage++) {
-      if (gpu_memory_buffer_manager->IsNativeGpuMemoryBufferConfiguration(
-              static_cast<gfx::BufferFormat>(format),
-              static_cast<gfx::BufferUsage>(usage)))
+      if (base::ContainsKey(
+              native_configurations,
+              std::make_pair(static_cast<gfx::BufferFormat>(format),
+                             static_cast<gfx::BufferUsage>(usage)))) {
         native_usage_support = base::StringPrintf(
             "%s%s %s", native_usage_support.c_str(),
             native_usage_support.empty() ? "" : ",",
             BufferUsageToString(static_cast<gfx::BufferUsage>(usage)));
+      }
     }
     if (native_usage_support.empty())
       native_usage_support = base::StringPrintf("Software only");
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/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 9f9fd012..afbf62a 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -53,7 +53,6 @@
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/compositor/surface_utils.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/common/gpu_stream_constants.h"
@@ -806,10 +805,13 @@
   renderer_settings.highp_threshold_min = 2048;
   renderer_settings.enable_color_correct_rendering =
       base::FeatureList::IsEnabled(features::kColorCorrectRendering);
+  auto* gpu_memory_buffer_manager = BrowserMainLoop::GetInstance()
+                                        ->gpu_channel_establish_factory()
+                                        ->GetGpuMemoryBufferManager();
   display_.reset(new cc::Display(
-      viz::ServerSharedBitmapManager::current(),
-      BrowserGpuMemoryBufferManager::current(), renderer_settings,
-      frame_sink_id_, std::move(display_output_surface), std::move(scheduler),
+      viz::ServerSharedBitmapManager::current(), gpu_memory_buffer_manager,
+      renderer_settings, frame_sink_id_, std::move(display_output_surface),
+      std::move(scheduler),
       base::MakeUnique<cc::TextureMailboxDeleter>(task_runner)));
 
   auto layer_tree_frame_sink =
@@ -819,7 +821,8 @@
                 vulkan_context_provider)
           : base::MakeUnique<cc::DirectLayerTreeFrameSink>(
                 frame_sink_id_, manager, display_.get(), context_provider,
-                nullptr, BrowserGpuMemoryBufferManager::current(),
+                nullptr /* worker_context_provider */,
+                gpu_memory_buffer_manager,
                 viz::ServerSharedBitmapManager::current());
 
   display_->SetVisible(true);
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 68b59b1..acaf9fd 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -19,7 +19,7 @@
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "content/common/cache_storage/cache_storage_types.h"
 #include "content/common/render_message_filter.mojom.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index caea5b7..711c8b48 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"
@@ -78,7 +78,6 @@
 #include "content/browser/field_trial_recorder.h"
 #include "content/browser/fileapi/fileapi_message_filter.h"
 #include "content/browser/frame_host/render_frame_message_filter.h"
-#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_client.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -2165,7 +2164,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/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 4532293..2db6b5e 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2145,11 +2145,11 @@
 void RenderWidgetHostImpl::OnShowDisambiguationPopup(
     const gfx::Rect& rect_pixels,
     const gfx::Size& size,
-    const cc::SharedBitmapId& id) {
+    const viz::SharedBitmapId& id) {
   DCHECK(!rect_pixels.IsEmpty());
   DCHECK(!size.IsEmpty());
 
-  std::unique_ptr<cc::SharedBitmap> bitmap =
+  std::unique_ptr<viz::SharedBitmap> bitmap =
       viz::ServerSharedBitmapManager::current()->GetSharedBitmapFromId(size,
                                                                        id);
   if (!bitmap) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 1f6ff8b..8ef5f936 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -26,8 +26,8 @@
 #include "base/timer/elapsed_timer.h"
 #include "build/build_config.h"
 #include "cc/ipc/compositor_frame_sink.mojom.h"
-#include "cc/resources/shared_bitmap.h"
 #include "cc/surfaces/frame_sink_id.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/browser/renderer_host/input/input_ack_handler.h"
 #include "content/browser/renderer_host/input/input_router_client.h"
@@ -662,7 +662,7 @@
   void OnUnlockMouse();
   void OnShowDisambiguationPopup(const gfx::Rect& rect_pixels,
                                  const gfx::Size& size,
-                                 const cc::SharedBitmapId& id);
+                                 const viz::SharedBitmapId& id);
   void OnSelectionBoundsChanged(
       const ViewHostMsg_SelectionBounds_Params& params);
   void OnSetNeedsBeginFrames(bool needs_begin_frames);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 489533b..6e22dd4 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -3245,7 +3245,7 @@
 
   for (size_t i = 0; i < (renderer_count - 1) * handles_per_frame; i++) {
     notifier.ChildAllocatedSharedBitmap(1, base::SharedMemoryHandle(),
-                                        cc::SharedBitmap::GenerateId());
+                                        viz::SharedBitmap::GenerateId());
   }
 
   // Hiding this last bitmap should evict all but two frames.
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/child/runtime_features.cc b/content/child/runtime_features.cc
index 8affb3fe..3461d89 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -395,6 +395,9 @@
       base::GetFieldTrialParamValue("PreviewsClientLoFi",
                                     "replace_server_placeholders") == "true");
 
+  WebRuntimeFeatures::EnableResourceLoadScheduler(
+      base::FeatureList::IsEnabled(features::kResourceLoadScheduler));
+
   // Enable explicitly enabled features, and then disable explicitly disabled
   // ones.
   if (command_line.HasSwitch(switches::kEnableBlinkFeatures)) {
diff --git a/content/common/DEPS b/content/common/DEPS
index 4ce7110..b11a706 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -2,6 +2,8 @@
   "-storage/browser",
 
   "+components/discardable_memory/common",
+  "+components/viz/common/quads",
+  "+components/viz/common/resources",
   "+components/payments",
   "+device/base/synchronization",
   "+services/resource_coordinator/public/interfaces",
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index ea71aa7..90227084 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -14,7 +14,7 @@
 #include "base/tracked_objects.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits_macros.h"
 #include "gpu/command_buffer/common/sync_token.h"
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/common/view_messages.h b/content/common/view_messages.h
index 8ca428f..c2e1d073 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -15,7 +15,7 @@
 #include "cc/ipc/cc_param_traits.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/compositor_frame.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits.h"
 #include "content/common/date_time_suggestion.h"
@@ -557,7 +557,7 @@
 // An acknowledgement to ViewHostMsg_ShowDisambiguationPopup to notify the
 // renderer process to release the magnified image.
 IPC_MESSAGE_ROUTED1(ViewMsg_ReleaseDisambiguationPopupBitmap,
-                    cc::SharedBitmapId /* id */)
+                    viz::SharedBitmapId /* id */)
 
 // If the ViewHostMsg_ShowDisambiguationPopup resulted in the user tapping
 // inside the popup, instruct the renderer to generate a synthetic tap at that
@@ -826,7 +826,7 @@
 IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDisambiguationPopup,
                     gfx::Rect, /* Border of touched targets */
                     gfx::Size, /* Size of zoomed image */
-                    cc::SharedBitmapId /* id */)
+                    viz::SharedBitmapId /* id */)
 
 // Message sent from renderer to the browser when the element that is focused
 // has been touched. A bool is passed in this message which indicates if the
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/BUILD.gn b/content/public/android/BUILD.gn
index 53ceaab2..434fc73 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -445,7 +445,9 @@
     "javatests/src/org/chromium/content/browser/ViewportTest.java",
     "javatests/src/org/chromium/content/browser/WebContentsObserverAndroidTest.java",
     "javatests/src/org/chromium/content/browser/accessibility/captioning/CaptioningChangeDelegateTest.java",
+    "javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplPixelTest.java",
     "javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java",
+    "javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTestBase.java",
     "javatests/src/org/chromium/content/browser/crypto/CipherFactoryTest.java",
     "javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java",
     "javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java",
@@ -472,6 +474,7 @@
   java_files = [
     "junit/src/org/chromium/content/browser/BindingManagerImplTest.java",
     "junit/src/org/chromium/content/browser/ChildConnectionAllocatorTest.java",
+    "junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java",
     "junit/src/org/chromium/content/browser/MenuDescriptorTest.java",
     "junit/src/org/chromium/content/browser/SpareChildConnectionTest.java",
     "junit/src/org/chromium/content/browser/TestChildProcessConnection.java",
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/ChildConnectionAllocator.java b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
index c1972fc..c9be272 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
@@ -241,7 +241,7 @@
             listener.onConnectionAllocated(this, connection);
         }
 
-        connection.start(mUseStrongBinding, serviceCallbackWrapper);
+        connection.start(mUseStrongBinding, serviceCallbackWrapper, false /* retryOnTimeout */);
         Log.d(TAG, "Allocator allocated and bound a connection, name: %s, slot: %d",
                 mServiceClassName, slot);
         return connection;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
index 1d56446..4ca70ed 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
@@ -27,6 +27,8 @@
 public class ChildProcessConnection {
     private static final String TAG = "ChildProcessConn";
 
+    private static final int BIND_SERVICE_TIMEOUT_IN_MS = 10 * 1000;
+
     /**
      * Used to notify the consumer about the process start. These callbacks will be invoked before
      * the ConnectionCallbacks.
@@ -177,6 +179,11 @@
     // call.
     private ConnectionCallback mConnectionCallback;
 
+    // Workaround bug on some android versions where bindService does not result in
+    // onServiceConnected for sandboxed services; see crbug.com/736066 for details.
+    // This is a delayed callback that will retry bindService with a delay.
+    private Runnable mOnServiceConnectedWatchDog;
+
     private IChildProcessService mService;
 
     // Set to true when the service connection callback runs. This differs from
@@ -290,7 +297,8 @@
      * @param serviceCallback (optional) callbacks invoked when the child process starts or fails to
      * start and when the service stops.
      */
-    public void start(boolean useStrongBinding, ServiceCallback serviceCallback) {
+    public void start(
+            boolean useStrongBinding, ServiceCallback serviceCallback, boolean retryOnTimeout) {
         assert LauncherThread.runningOnLauncherThread();
         try {
             TraceEvent.begin("ChildProcessConnection.start");
@@ -300,8 +308,10 @@
 
             mServiceCallback = serviceCallback;
 
+            resetWatchdog(useStrongBinding, serviceCallback, retryOnTimeout);
             if (!bind(useStrongBinding)) {
                 Log.e(TAG, "Failed to establish the service connection.");
+                cancelWatchDog();
                 // We have to notify the caller so that they can free-up associated resources.
                 // TODO(ppi): Can we hard-fail here?
                 notifyChildProcessDied();
@@ -349,14 +359,17 @@
      */
     public void stop() {
         assert LauncherThread.runningOnLauncherThread();
+        cancelWatchDog();
         unbind();
         mService = null;
         mConnectionParams = null;
         notifyChildProcessDied();
     }
 
-    private void onServiceConnectedOnLauncherThread(IBinder service) {
+    @VisibleForTesting
+    public void onServiceConnectedOnLauncherThread(IBinder service) {
         assert LauncherThread.runningOnLauncherThread();
+        cancelWatchDog();
         // A flag from the parent class ensures we run the post-connection logic only once
         // (instead of once per each ChildServiceConnection).
         if (mDidOnServiceConnected) {
@@ -403,7 +416,8 @@
         }
     }
 
-    private void onServiceDisconnectedOnLauncherThread() {
+    @VisibleForTesting
+    public void onServiceDisconnectedOnLauncherThread() {
         assert LauncherThread.runningOnLauncherThread();
         // Ensure that the disconnection logic runs only once (instead of once per each
         // ChildServiceConnection).
@@ -482,12 +496,16 @@
     protected void unbind() {
         assert LauncherThread.runningOnLauncherThread();
         mUnbound = true;
+        unbindAll();
+        // Note that we don't update the waived bound only state here as to preserve the state when
+        // disconnected.
+    }
+
+    private void unbindAll() {
         mStrongBinding.unbind();
         mWaivedBinding.unbind();
         mModerateBinding.unbind();
         mInitialBinding.unbind();
-        // Note that we don't update the waived bound only state here as to preserve the state when
-        // disconnected.
     }
 
     public boolean isInitialBindingBound() {
@@ -603,6 +621,34 @@
         }
     }
 
+    private void resetWatchdog(final boolean useStrongBinding,
+            final ServiceCallback serviceCallback, final boolean retryOnTimeout) {
+        assert LauncherThread.runningOnLauncherThread();
+        cancelWatchDog();
+        assert mOnServiceConnectedWatchDog == null;
+        mOnServiceConnectedWatchDog = new Runnable() {
+            @Override
+            public void run() {
+                assert mOnServiceConnectedWatchDog == this;
+                assert !mDidOnServiceConnected;
+                assert mServiceCallback == null;
+                mOnServiceConnectedWatchDog = null;
+                // TODO(boliu): Add a UMA here.
+                if (!retryOnTimeout) return;
+                unbindAll();
+                start(useStrongBinding, serviceCallback, retryOnTimeout);
+            }
+        };
+        LauncherThread.postDelayed(mOnServiceConnectedWatchDog, BIND_SERVICE_TIMEOUT_IN_MS);
+    }
+
+    private void cancelWatchDog() {
+        assert LauncherThread.runningOnLauncherThread();
+        if (mOnServiceConnectedWatchDog == null) return;
+        LauncherThread.removeCallbacks(mOnServiceConnectedWatchDog);
+        mOnServiceConnectedWatchDog = null;
+    }
+
     @VisibleForTesting
     protected ChildServiceConnection createServiceConnection(int bindFlags) {
         assert LauncherThread.runningOnLauncherThread();
@@ -622,4 +668,9 @@
         return new ChildProcessConnection(context, serviceName, bindAsExternalService,
                 serviceBundle, creationParams, false /* doBind */);
     }
+
+    @VisibleForTesting
+    public boolean didOnServiceConnectedForTesting() {
+        return mDidOnServiceConnected;
+    }
 }
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/androidoverlay/AndroidOverlayProviderImpl.java b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/AndroidOverlayProviderImpl.java
index b47aeb6..03637d8b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/AndroidOverlayProviderImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/AndroidOverlayProviderImpl.java
@@ -66,8 +66,8 @@
         startThreadIfNeeded();
         mNumOverlays++;
 
-        DialogOverlayImpl impl =
-                new DialogOverlayImpl(client, config, mHandler, mNotifyReleasedRunnable);
+        DialogOverlayImpl impl = new DialogOverlayImpl(
+                client, config, mHandler, mNotifyReleasedRunnable, false /* asPanel*/);
         DialogOverlayImpl.MANAGER.bind(impl, request);
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayCore.java b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayCore.java
index a9391e6..9cfebaa 100644
--- a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayCore.java
@@ -53,6 +53,9 @@
     // Most recent layout parameters.
     private WindowManager.LayoutParams mLayoutParams;
 
+    // If true, then we'll be a panel rather than media overlay.  This is for testing.
+    private boolean mAsPanel;
+
     /**
      * Construction may be called from a random thread, for simplicity.  Call initialize from the
      * proper thread before doing anything else.
@@ -64,9 +67,12 @@
      * @param dialog the dialog, which uses our current thread as the UI thread.
      * @param config initial config.
      * @param host host interface, for sending messages that (probably) need to thread hop.
+     * @param asPanel if true, then we'll be a panel.  This is intended for tests only.
      */
-    public void initialize(Context context, AndroidOverlayConfig config, Host host) {
+    public void initialize(
+            Context context, AndroidOverlayConfig config, Host host, boolean asPanel) {
         mHost = host;
+        mAsPanel = asPanel;
 
         mDialog = new Dialog(context, android.R.style.Theme_NoDisplay);
         mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -184,7 +190,8 @@
         // Use a media surface, which is what SurfaceView uses by default.  For
         // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
         // move the dialog over the CompositorView.
-        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+        layoutParams.type = mAsPanel ? WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
+                                     : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 
         layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
diff --git a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
index e49bd8c..261658a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
@@ -54,9 +54,10 @@
      * @param handler handler that posts to the overlay thread.  This is the android UI thread that
      * the dialog uses, not the browser UI thread.
      * @param provider the overlay provider that owns us.
+     * @param asPanel the overlay should be a panel, above the compositor.  This is for testing.
      */
     public DialogOverlayImpl(AndroidOverlayClient client, final AndroidOverlayConfig config,
-            Handler overlayHandler, Runnable releasedRunnable) {
+            Handler overlayHandler, Runnable releasedRunnable, final boolean asPanel) {
         ThreadUtils.assertOnUiThread();
 
         mClient = client;
@@ -66,19 +67,24 @@
         mDialogCore = new DialogOverlayCore();
         mHoppingHost = new ThreadHoppingHost(this);
 
+        // Register to get token updates.  Note that this may not call us back directly, since
+        // |mDialogCore| hasn't been initialized yet.
+        mNativeHandle = nativeInit(config.routingToken.high, config.routingToken.low);
+        assert mNativeHandle != 0;
+
         // Post init to the overlay thread.
         final DialogOverlayCore dialogCore = mDialogCore;
         final Context context = ContextUtils.getApplicationContext();
+        nativeGetCompositorOffset(mNativeHandle, config.rect);
         mOverlayHandler.post(new Runnable() {
             @Override
             public void run() {
-                dialogCore.initialize(context, config, mHoppingHost);
+                dialogCore.initialize(context, config, mHoppingHost, asPanel);
             }
         });
 
-        // Register to get token updates.
-        mNativeHandle = nativeInit(config.routingToken.high, config.routingToken.low);
-        assert mNativeHandle != 0;
+        // Now that |mDialogCore| has been initialized, we are ready for token callbacks.
+        nativeCompleteInit(mNativeHandle);
     }
 
     // AndroidOverlay impl.
@@ -151,7 +157,7 @@
 
     // Receive the compositor offset, as part of scheduleLayout.  Adjust the layout position.
     @CalledByNative
-    private void receiveCompositorOffset(Rect rect, int x, int y) {
+    private static void receiveCompositorOffset(Rect rect, int x, int y) {
         rect.x += x;
         rect.y += y;
     }
@@ -271,11 +277,18 @@
 
     /**
      * Initializes native side.  Will register for onWindowToken callbacks on |this|.  Returns a
-     * handle that should be provided to nativeDestroy.
+     * handle that should be provided to nativeDestroy.  This will not call back with a window token
+     * immediately.  Call nativeCompleteInit() for the initial token.
      */
     private native long nativeInit(long high, long low);
 
     /**
+     * Notify the native side that we are ready for token / dismissed callbacks.  This may result in
+     * a callback before it returns.
+     */
+    private native void nativeCompleteInit(long nativeDialogOverlayImpl);
+
+    /**
      * Stops native side and deallocates |handle|.
      */
     private native void nativeDestroy(long nativeDialogOverlayImpl);
@@ -298,4 +311,10 @@
      * @param surfaceId Id that was returned by registerSurface.
      */
     private static native void nativeUnregisterSurface(int surfaceId);
+
+    /**
+     * Look up and return a surface.
+     * @param surfaceId Id that was returned by registerSurface.
+     */
+    /* package */ static native Surface nativeLookupSurfaceForTesting(int surfaceId);
 }
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..66110fd 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
@@ -357,7 +357,8 @@
                                                     connection);
                                         }
                                     }
-                                });
+                                },
+                                false /* retryOnTimeout */);
                         return connection;
                     }
                 });
@@ -507,6 +508,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/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplPixelTest.java b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplPixelTest.java
new file mode 100644
index 0000000..8992018
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplPixelTest.java
@@ -0,0 +1,267 @@
+// 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.content.browser.androidoverlay;
+
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.view.Surface;
+
+import org.junit.Assert;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.base.test.util.UrlUtils;
+import org.chromium.content.browser.ContentViewCore;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Pixel tests for DialogOverlayImpl.  These use UiAutomation, so they only run in JB or above.
+ * TODO(liberato): Convert to junit4.
+ */
+@MinAndroidSdkLevel(Build.VERSION_CODES.JELLY_BEAN_MR2)
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+public class DialogOverlayImplPixelTest extends DialogOverlayImplTestBase {
+    // Color that we'll fill the overlay with.
+    private static final int OVERLAY_FILL_COLOR = Color.BLUE;
+
+    // CSS coordinates of a div that we'll try to cover with an overlay.
+    private static final int DIV_X_CSS = 10;
+    private static final int DIV_Y_CSS = 20;
+    private static final int DIV_WIDTH_CSS = 300;
+    private static final int DIV_HEIGHT_CSS = 200;
+
+    // Provide a solid-color div that's positioned / sized by DIV_*_CSS.
+    private static final String TEST_PAGE_STYLE = "<style>"
+            + "div {"
+            + "left: " + DIV_X_CSS + "px;"
+            + "top: " + DIV_Y_CSS + "px;"
+            + "width: " + DIV_WIDTH_CSS + "px;"
+            + "height: " + DIV_HEIGHT_CSS + "px;"
+            + "position: absolute;"
+            + "background: red;"
+            + "}"
+            + "</style>";
+    private static final String TEST_PAGE_DATA_URL = UrlUtils.encodeHtmlDataUri(
+            "<html>" + TEST_PAGE_STYLE + "<body><div></div></body></html>");
+
+    // Number of retries for various race-prone operations.
+    private static final int NUM_RETRIES = 10;
+
+    // Delay (msec) between retries.
+    private static final int RETRY_DELAY = 50;
+
+    // Number of rows and columns that we consider as optional due to rounding and blending diffs.
+    private static final int FUZZY_PIXELS = 1;
+
+    // DIV_*_CSS converted to screen pixels.
+    int mDivXPx;
+    int mDivYPx;
+    int mDivWidthPx;
+    int mDivHeightPx;
+
+    // Target area boundaries.
+    // We allow a range because of page / device scaling.  The size of the div and the size of the
+    // area of overlap can be off by a pixel in either direction.  The div can be blended around the
+    // edge, while the overlay position can round differently.
+    int mTargetAreaMinPx;
+    int mTargetAreaMaxPx;
+
+    // Maximum status bar height that we'll work with.  This just lets us restrict the area of the
+    // screenshot that we inspect, since it's slow.  This should also include the URL bar.
+    private static final int mStatusBarMaxHeightPx = 300;
+
+    // Area of interest that contains the div, since the whole image is big.
+    Rect mAreaOfInterestPx;
+
+    // Screenshot of the test page, before we do anything.
+    Bitmap mInitialScreenshot;
+
+    @Override
+    protected String getInitialUrl() {
+        return TEST_PAGE_DATA_URL;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        takeScreenshotOfBackground();
+    }
+
+    // Take a screenshot via UiAutomation, which captures all overlays.
+    Bitmap takeScreenshot() {
+        return getInstrumentation().getUiAutomation().takeScreenshot();
+    }
+
+    // Fill |surface| with OVERLAY_FILL_COLOR and return a screenshot.  Note that we have no idea
+    // how long it takes before the image posts, so the screenshot might not reflect it.  Be
+    // prepared to retry.  Note that we always draw the same thing, so it's okay if a retry gets a
+    // screenshot of a previous surface; they're identical.
+    Bitmap fillSurface(Surface surface) {
+        Canvas canvas = surface.lockCanvas(null);
+        canvas.drawColor(OVERLAY_FILL_COLOR);
+        surface.unlockCanvasAndPost(canvas);
+        return takeScreenshot();
+    }
+
+    int convertCSSToScreenPixels(int css) {
+        ContentViewCore cvc = getContentViewCore();
+        return (int) (css * cvc.getPageScaleFactor() * cvc.getDeviceScaleFactor());
+    }
+
+    // Since ContentShell makes our solid color div have some textured background, we have to be
+    // somewhat lenient here.  Plus, sometimes the edges of the div are blended.
+    boolean isApproximatelyRed(int color) {
+        int r = Color.red(color);
+        return r > 100 && Color.green(color) < r && Color.blue(color) < r;
+    }
+
+    // Take a screenshot, and wait until we get one that has the background div in it.
+    void takeScreenshotOfBackground() {
+        mAreaOfInterestPx = new Rect();
+        for (int retries = 0; retries < NUM_RETRIES; retries++) {
+            // Compute the div position in screen pixels.  We recompute these since they sometimes
+            // take a while to settle, also.
+            mDivXPx = convertCSSToScreenPixels(DIV_X_CSS);
+            mDivYPx = convertCSSToScreenPixels(DIV_Y_CSS);
+            mDivWidthPx = convertCSSToScreenPixels(DIV_WIDTH_CSS);
+            mDivHeightPx = convertCSSToScreenPixels(DIV_HEIGHT_CSS);
+
+            // Allow one edge on each side to be non-overlapping or misdetected.
+            mTargetAreaMaxPx = mDivWidthPx * mDivHeightPx;
+            mTargetAreaMinPx = (mDivWidthPx - FUZZY_PIXELS) * (mDivHeightPx - FUZZY_PIXELS);
+
+            // Don't read the whole bitmap.  It's quite big.  Assume that the status bar is only at
+            // the top, and that it's at most mStatusBarMaxHeightPx px tall.  We also allow a bit of
+            // room on each side for rounding issues.  Setting these too large just slows down the
+            // test, without affecting the result.
+            mAreaOfInterestPx.left = mDivXPx - FUZZY_PIXELS;
+            mAreaOfInterestPx.top = mDivYPx - FUZZY_PIXELS;
+            mAreaOfInterestPx.right = mDivXPx + mDivWidthPx - 1 + FUZZY_PIXELS;
+            mAreaOfInterestPx.bottom = mDivYPx + mDivHeightPx + mStatusBarMaxHeightPx;
+
+            mInitialScreenshot = takeScreenshot();
+
+            int area = 0;
+            for (int ry = mAreaOfInterestPx.top; ry <= mAreaOfInterestPx.bottom; ry++) {
+                for (int rx = mAreaOfInterestPx.left; rx <= mAreaOfInterestPx.right; rx++) {
+                    if (isApproximatelyRed(mInitialScreenshot.getPixel(rx, ry))) area++;
+                }
+            }
+
+            // It's okay if we have some randomly colored other pixels.
+            if (area >= mTargetAreaMinPx) return;
+
+            try {
+                Thread.sleep(RETRY_DELAY);
+            } catch (Exception e) {
+            }
+        }
+
+        Assert.assertTrue(false);
+    }
+
+    // Count how many pixels in the div are covered by OVERLAY_FILL_COLOR in |overlayScreenshot|,
+    // and return it.
+    int countDivPixelsCoveredByOverlay(Bitmap overlayScreenshot) {
+        // Find pixels that changed from the source color to the target color.  This should avoid
+        // issues like changes in the status bar, unless we're really unlucky.  It assumes that the
+        // div is actually the expected size; coloring the entire page red would fool this.
+        int area = 0;
+        for (int ry = mAreaOfInterestPx.top; ry <= mAreaOfInterestPx.bottom; ry++) {
+            for (int rx = mAreaOfInterestPx.left; rx <= mAreaOfInterestPx.right; rx++) {
+                if (isApproximatelyRed(mInitialScreenshot.getPixel(rx, ry))
+                        && overlayScreenshot.getPixel(rx, ry) == OVERLAY_FILL_COLOR) {
+                    area++;
+                }
+            }
+        }
+
+        return area;
+    }
+
+    // Assert that |surface| exactly covers the target div on the page.  Note that we assume that
+    // you have not drawn anything to |surface| yet, so that we can still see the div.
+    void assertDivIsExactlyCovered(Surface surface) {
+        // Draw two colors, and count as the area the ones that change between screenshots.  This
+        // lets us notice if the status bar is occluding something, even if it happens to be the
+        // same color.
+        int area = 0;
+        int targetArea = mDivWidthPx * mDivHeightPx;
+        for (int retries = 0; retries < NUM_RETRIES; retries++) {
+            // We fill the overlay every time, in case a resize was pending.  Eventually, we should
+            // reach a steady-state where the surface is resized, and this (or a previous) filled-in
+            // surface is on the screen.
+            Bitmap overlayScreenshot = fillSurface(surface);
+            area = countDivPixelsCoveredByOverlay(overlayScreenshot);
+            if (area >= mTargetAreaMinPx && area <= mTargetAreaMaxPx) return;
+
+            // There are several reasons this can fail besides being broken.  We don't know how long
+            // it takes for fillSurface()'s output to make it to the display.  We also don't know
+            // how long scheduleLayout() takes.  Just try a few times, since the whole thing should
+            // take only a frame or two to settle.
+            try {
+                Thread.sleep(RETRY_DELAY);
+            } catch (Exception e) {
+            }
+        }
+
+        // Assert so that we get a helpful message in the log.
+        Assert.assertEquals(targetArea, area);
+    }
+
+    // Wait for |overlay| to become ready, get its surface, and return it.
+    Surface waitForSurface(DialogOverlayImpl overlay) throws Exception {
+        Assert.assertNotNull(overlay);
+        final Client.Event event = getClient().nextEvent();
+        Assert.assertTrue(event.surfaceKey > 0);
+        return ThreadUtils.runOnUiThreadBlocking(new Callable<Surface>() {
+            @Override
+            public Surface call() {
+                return DialogOverlayImpl.nativeLookupSurfaceForTesting((int) event.surfaceKey);
+            }
+        });
+    }
+
+    @MediumTest
+    @Feature({"AndroidOverlay"})
+    public void testInitialPosition() throws Exception {
+        // Test that the initial position supplied for the overlay covers the <div> we created.
+        final DialogOverlayImpl overlay =
+                createOverlay(mDivXPx, mDivYPx, mDivWidthPx, mDivHeightPx);
+        Surface surface = waitForSurface(overlay);
+
+        assertDivIsExactlyCovered(surface);
+    }
+
+    @MediumTest
+    @Feature({"AndroidOverlay"})
+    public void testScheduleLayout() throws Exception {
+        // Test that scheduleLayout() moves the overlay to cover the <div>.
+        final DialogOverlayImpl overlay = createOverlay(0, 0, 10, 10);
+        Surface surface = waitForSurface(overlay);
+
+        final org.chromium.gfx.mojom.Rect rect = new org.chromium.gfx.mojom.Rect();
+        rect.x = mDivXPx;
+        rect.y = mDivYPx;
+        rect.width = mDivWidthPx;
+        rect.height = mDivHeightPx;
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                overlay.scheduleLayout(rect);
+            }
+        });
+
+        assertDivIsExactlyCovered(surface);
+    }
+}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java
index 8f44ed7..ab8e1595 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTest.java
@@ -4,196 +4,23 @@
 
 package org.chromium.content.browser.androidoverlay;
 
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.support.test.filters.SmallTest;
 
 import org.junit.Assert;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
-import org.chromium.content.browser.framehost.RenderFrameHostImpl;
-import org.chromium.content_shell_apk.ContentShellTestBase;
-import org.chromium.media.mojom.AndroidOverlayClient;
-import org.chromium.media.mojom.AndroidOverlayConfig;
-import org.chromium.mojo.common.mojom.UnguessableToken;
-import org.chromium.mojo.system.MojoException;
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Tests for DialogOverlayImpl.
+ * TODO(liberato): Convert to junit4.
  */
-public class DialogOverlayImplTest extends ContentShellTestBase {
+public class DialogOverlayImplTest extends DialogOverlayImplTestBase {
     private static final String BLANK_URL = "about://blank";
 
-    // The routing token that we'll use to create overlays.
-    UnguessableToken mRoutingToken;
-
-    // overlay-ui thread.
-    HandlerThread mOverlayUiThread;
-    Handler mOverlayUiHandler;
-
-    // Runnable that will be called on the browser UI thread when an overlay is released.
-    Runnable mReleasedRunnable;
-
-    // True if we should create a secure overlay.
-    boolean mSecure;
-
-    /**
-     * AndroidOverlay client that supports waiting operations for callbacks.  One may call
-     * nextEvent() to get the next callback, waiting if needed.
-     */
-    public static class Client implements AndroidOverlayClient {
-        // AndroidOverlayClient
-        public static final int SURFACE_READY = 0;
-        public static final int DESTROYED = 1;
-        public static final int CLOSE = 2;
-        public static final int CONNECTION_ERROR = 2;
-        // AndroidOverlayProviderImpl.Callbacks
-        public static final int RELEASED = 100;
-        // Internal to test only.
-        public static final int TEST_MARKER = 200;
-
-        /**
-         * Records one callback event.
-         */
-        public static class Event {
-            public Event(int which) {
-                this.which = which;
-            }
-
-            public Event(int which, long surfaceKey) {
-                this.which = which;
-                this.surfaceKey = surfaceKey;
-            }
-
-            public Event(int which, MojoException exception) {
-                this.which = which;
-            }
-
-            public int which;
-            public long surfaceKey;
-        }
-
-        private ArrayBlockingQueue<Event> mPending;
-
-        public Client() {
-            mPending = new ArrayBlockingQueue<Event>(10);
-        }
-
-        @Override
-        public void onSurfaceReady(long surfaceKey) {
-            mPending.add(new Event(SURFACE_READY, surfaceKey));
-        }
-
-        @Override
-        public void onDestroyed() {
-            mPending.add(new Event(DESTROYED));
-        }
-
-        @Override
-        public void close() {
-            mPending.add(new Event(CLOSE));
-        }
-
-        @Override
-        public void onConnectionError(MojoException exception) {
-            mPending.add(new Event(CONNECTION_ERROR, exception));
-        }
-
-        // This isn't part of the overlay client.  It's called by the overlay to indicate that it
-        // has been released by the client, but it's routed to us anyway.  It's on the Browser UI
-        // thread, and it's convenient for us to keep track of it here.
-        public void notifyReleased() {
-            mPending.add(new Event(RELEASED));
-        }
-
-        // Inject a marker event, so that the test can checkpoint things.
-        public void injectMarkerEvent() {
-            mPending.add(new Event(TEST_MARKER));
-        }
-
-        // Wait for something to happen.  We enforce a timeout, since the test harness doesn't
-        // always seem to fail the test when it times out.  Plus, it takes ~minute for that, but
-        // none of our messages should take that long.
-        Event nextEvent() {
-            try {
-                return mPending.poll(500, TimeUnit.MILLISECONDS);
-            } catch (InterruptedException e) {
-                Assert.fail(e.toString());
-            }
-
-            // NOTREACHED
-            return null;
-        }
-
-        boolean isEmpty() {
-            return mPending.size() == 0;
-        }
-    }
-
-    private Client mClient = new Client();
-
     @Override
-    public void setUp() throws Exception {
-        super.setUp();
-
-        startActivityWithTestUrl(BLANK_URL);
-
-        // Fetch the routing token.
-        mRoutingToken =
-                ThreadUtils.runOnUiThreadBlockingNoException(new Callable<UnguessableToken>() {
-                    @Override
-                    public UnguessableToken call() {
-                        RenderFrameHostImpl host =
-                                (RenderFrameHostImpl) getWebContents().getMainFrame();
-                        org.chromium.base.UnguessableToken routingToken =
-                                host.getAndroidOverlayRoutingToken();
-                        UnguessableToken mojoToken = new UnguessableToken();
-                        mojoToken.high = routingToken.getHighForSerialization();
-                        mojoToken.low = routingToken.getLowForSerialization();
-                        return mojoToken;
-                    }
-                });
-
-        // Set up the overlay UI thread
-        mOverlayUiThread = new HandlerThread("TestOverlayUI");
-        mOverlayUiThread.start();
-        mOverlayUiHandler = new Handler(mOverlayUiThread.getLooper());
-
-        // Just delegate to |mClient| when an overlay is released.
-        mReleasedRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mClient.notifyReleased();
-            }
-        };
-    }
-
-    // Create an overlay with the given parameters and return it.
-    DialogOverlayImpl createOverlay(final int x, final int y, final int width, final int height) {
-        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<DialogOverlayImpl>() {
-            @Override
-            public DialogOverlayImpl call() {
-                AndroidOverlayConfig config = new AndroidOverlayConfig();
-                config.routingToken = mRoutingToken;
-                config.rect = new org.chromium.gfx.mojom.Rect();
-                config.rect.x = x;
-                config.rect.y = y;
-                config.rect.width = width;
-                config.rect.height = height;
-                config.secure = mSecure;
-                HandlerThread overlayUiThread = new HandlerThread("TestOverlayUI");
-                overlayUiThread.start();
-                DialogOverlayImpl impl = new DialogOverlayImpl(
-                        mClient, config, mOverlayUiHandler, mReleasedRunnable);
-
-                return impl;
-            }
-        });
+    protected String getInitialUrl() {
+        return BLANK_URL;
     }
 
     @SmallTest
@@ -202,7 +29,7 @@
         final DialogOverlayImpl overlay = createOverlay(0, 0, 10, 10);
 
         // We should get a new overlay with a valid surface key.
-        Client.Event event = mClient.nextEvent();
+        Client.Event event = getClient().nextEvent();
         Assert.assertEquals(Client.SURFACE_READY, event.which);
         Assert.assertTrue(event.surfaceKey > 0);
 
@@ -214,7 +41,7 @@
                 overlay.close();
             }
         });
-        Assert.assertEquals(Client.RELEASED, mClient.nextEvent().which);
+        Assert.assertEquals(Client.RELEASED, getClient().nextEvent().which);
     }
 
     @SmallTest
@@ -226,7 +53,7 @@
         Assert.assertNotNull(overlay);
 
         // We should be notified that the overlay is destroyed.
-        Client.Event event = mClient.nextEvent();
+        Client.Event event = getClient().nextEvent();
         Assert.assertEquals(Client.DESTROYED, event.which);
     }
 
@@ -237,7 +64,7 @@
         final DialogOverlayImpl overlay = createOverlay(0, 0, 10, 10);
 
         // Wait for the surface.
-        Assert.assertEquals(Client.SURFACE_READY, mClient.nextEvent().which);
+        Assert.assertEquals(Client.SURFACE_READY, getClient().nextEvent().which);
         final org.chromium.gfx.mojom.Rect rect = new org.chromium.gfx.mojom.Rect();
         rect.x = 100;
         rect.y = 200;
@@ -251,7 +78,7 @@
         });
 
         // No additional messages should have arrived.
-        Assert.assertTrue(mClient.isEmpty());
+        Assert.assertTrue(getClient().isEmpty());
     }
 
     @SmallTest
@@ -264,7 +91,7 @@
         Assert.assertNotNull(overlay);
 
         // We should get a new overlay with a valid surface key.
-        Client.Event event = mClient.nextEvent();
+        Client.Event event = getClient().nextEvent();
         Assert.assertEquals(Client.SURFACE_READY, event.which);
         Assert.assertTrue(event.surfaceKey > 0);
     }
@@ -281,15 +108,15 @@
                 overlay.close();
             }
         });
-        Assert.assertEquals(Client.RELEASED, mClient.nextEvent().which);
+        Assert.assertEquals(Client.RELEASED, getClient().nextEvent().which);
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 overlay.close();
-                mClient.injectMarkerEvent();
+                getClient().injectMarkerEvent();
             }
         });
-        Assert.assertEquals(Client.TEST_MARKER, mClient.nextEvent().which);
+        Assert.assertEquals(Client.TEST_MARKER, getClient().nextEvent().which);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTestBase.java b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTestBase.java
new file mode 100644
index 0000000..aec3631
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/androidoverlay/DialogOverlayImplTestBase.java
@@ -0,0 +1,201 @@
+// 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.content.browser.androidoverlay;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import org.junit.Assert;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.content.browser.framehost.RenderFrameHostImpl;
+import org.chromium.content_shell_apk.ContentShellTestBase;
+import org.chromium.media.mojom.AndroidOverlayClient;
+import org.chromium.media.mojom.AndroidOverlayConfig;
+import org.chromium.mojo.common.mojom.UnguessableToken;
+import org.chromium.mojo.system.MojoException;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for tests for DialogOverlayImpl.
+ */
+public abstract class DialogOverlayImplTestBase extends ContentShellTestBase {
+    // overlay-ui thread.
+    private HandlerThread mOverlayUiThread;
+    private Handler mOverlayUiHandler;
+
+    // Runnable that will be called on the browser UI thread when an overlay is released.
+    private Runnable mReleasedRunnable;
+
+    // The routing token that we'll use to create overlays.  This may be modified by the tests prior
+    // to calling createOverlay().
+    protected UnguessableToken mRoutingToken;
+
+    // True if we should create a secure overlay.
+    protected boolean mSecure;
+
+    /**
+     * AndroidOverlay client that supports waiting operations for callbacks.  One may call
+     * nextEvent() to get the next callback, waiting if needed.
+     */
+    public static class Client implements AndroidOverlayClient {
+        // AndroidOverlayClient
+        public static final int SURFACE_READY = 0;
+        public static final int DESTROYED = 1;
+        public static final int CLOSE = 2;
+        public static final int CONNECTION_ERROR = 2;
+        // AndroidOverlayProviderImpl.Callbacks
+        public static final int RELEASED = 100;
+        // Internal to test only.
+        public static final int TEST_MARKER = 200;
+
+        /**
+         * Records one callback event.
+         */
+        public static class Event {
+            public Event(int which) {
+                this.which = which;
+            }
+
+            public Event(int which, long surfaceKey) {
+                this.which = which;
+                this.surfaceKey = surfaceKey;
+            }
+
+            public Event(int which, MojoException exception) {
+                this.which = which;
+            }
+
+            public int which;
+            public long surfaceKey;
+        }
+
+        private ArrayBlockingQueue<Event> mPending;
+
+        public Client() {
+            mPending = new ArrayBlockingQueue<Event>(10);
+        }
+
+        @Override
+        public void onSurfaceReady(long surfaceKey) {
+            mPending.add(new Event(SURFACE_READY, surfaceKey));
+        }
+
+        @Override
+        public void onDestroyed() {
+            mPending.add(new Event(DESTROYED));
+        }
+
+        @Override
+        public void close() {
+            mPending.add(new Event(CLOSE));
+        }
+
+        @Override
+        public void onConnectionError(MojoException exception) {
+            mPending.add(new Event(CONNECTION_ERROR, exception));
+        }
+
+        // This isn't part of the overlay client.  It's called by the overlay to indicate that it
+        // has been released by the client, but it's routed to us anyway.  It's on the Browser UI
+        // thread, and it's convenient for us to keep track of it here.
+        public void notifyReleased() {
+            mPending.add(new Event(RELEASED));
+        }
+
+        // Inject a marker event, so that the test can checkpoint things.
+        public void injectMarkerEvent() {
+            mPending.add(new Event(TEST_MARKER));
+        }
+
+        // Wait for something to happen.  We enforce a timeout, since the test harness doesn't
+        // always seem to fail the test when it times out.  Plus, it takes ~minute for that, but
+        // none of our messages should take that long.
+        Event nextEvent() {
+            try {
+                return mPending.poll(500, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                Assert.fail(e.toString());
+            }
+
+            // NOTREACHED
+            return null;
+        }
+
+        boolean isEmpty() {
+            return mPending.size() == 0;
+        }
+    }
+
+    private Client mClient = new Client();
+
+    // Return the URL to start with.
+    protected abstract String getInitialUrl();
+
+    protected Client getClient() {
+        return mClient;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        launchContentShellWithUrl(getInitialUrl());
+        waitForActiveShellToBeDoneLoading(); // Do we need this?
+
+        // Fetch the routing token.
+        mRoutingToken =
+                ThreadUtils.runOnUiThreadBlockingNoException(new Callable<UnguessableToken>() {
+                    @Override
+                    public UnguessableToken call() {
+                        RenderFrameHostImpl host =
+                                (RenderFrameHostImpl) getWebContents().getMainFrame();
+                        org.chromium.base.UnguessableToken routingToken =
+                                host.getAndroidOverlayRoutingToken();
+                        UnguessableToken mojoToken = new UnguessableToken();
+                        mojoToken.high = routingToken.getHighForSerialization();
+                        mojoToken.low = routingToken.getLowForSerialization();
+                        return mojoToken;
+                    }
+                });
+
+        // Set up the overlay UI thread
+        mOverlayUiThread = new HandlerThread("TestOverlayUI");
+        mOverlayUiThread.start();
+        mOverlayUiHandler = new Handler(mOverlayUiThread.getLooper());
+
+        // Just delegate to |mClient| when an overlay is released.
+        mReleasedRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mClient.notifyReleased();
+            }
+        };
+    }
+
+    // Create an overlay with the given parameters and return it.
+    DialogOverlayImpl createOverlay(final int x, final int y, final int width, final int height) {
+        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<DialogOverlayImpl>() {
+            @Override
+            public DialogOverlayImpl call() {
+                AndroidOverlayConfig config = new AndroidOverlayConfig();
+                config.routingToken = mRoutingToken;
+                config.rect = new org.chromium.gfx.mojom.Rect();
+                config.rect.x = x;
+                config.rect.y = y;
+                config.rect.width = width;
+                config.rect.height = height;
+                config.secure = mSecure;
+                DialogOverlayImpl impl = new DialogOverlayImpl(
+                        mClient, config, mOverlayUiHandler, mReleasedRunnable, true /* asPanel */);
+
+                return impl;
+            }
+        });
+    }
+}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
index 2711464..7963b33 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
@@ -49,7 +49,8 @@
                 new ComponentName(packageName, "TestService"), false /* bindAsExternalService */,
                 null /* serviceBundle */, creationParams);
         connection.setPid(pid);
-        connection.start(false /* useStrongBinding */, null /* serviceCallback */);
+        connection.start(false /* useStrongBinding */, null /* serviceCallback */,
+                false /* retryOnTimeout */);
         if (manager != null) {
             manager.addNewConnection(pid, connection);
         }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/ChildConnectionAllocatorTest.java b/content/public/android/junit/src/org/chromium/content/browser/ChildConnectionAllocatorTest.java
index 8c68dd28..91a09e8 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/ChildConnectionAllocatorTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/ChildConnectionAllocatorTest.java
@@ -74,7 +74,8 @@
                     }
                 })
                         .when(mConnection)
-                        .start(anyBoolean(), any(ChildProcessConnection.ServiceCallback.class));
+                        .start(anyBoolean(), any(ChildProcessConnection.ServiceCallback.class),
+                                anyBoolean());
             }
             return mConnection;
         }
@@ -109,7 +110,8 @@
                 }
             })
                     .when(mConnection)
-                    .start(anyBoolean(), any(ChildProcessConnection.ServiceCallback.class));
+                    .start(anyBoolean(), any(ChildProcessConnection.ServiceCallback.class),
+                            anyBoolean());
         }
 
         public void simulateServiceProcessDying() {
@@ -161,7 +163,7 @@
 
         verify(connection, times(1))
                 .start(eq(false) /* useStrongBinding */,
-                        any(ChildProcessConnection.ServiceCallback.class));
+                        any(ChildProcessConnection.ServiceCallback.class), anyBoolean());
         verify(listener, times(1)).onConnectionAllocated(mAllocator, connection);
         assertTrue(mAllocator.anyConnectionAllocated());
     }
@@ -199,7 +201,8 @@
             allocator.setConnectionFactoryForTesting(mTestConnectionFactory);
             ChildProcessConnection connection = allocator.allocate(
                     null /* context */, null /* serviceBundle */, mServiceCallback);
-            verify(connection, times(0)).start(useStrongBinding, mServiceCallback);
+            verify(connection, times(0))
+                    .start(useStrongBinding, mServiceCallback, false /* retryOnTimeout */);
         }
     }
 
@@ -262,7 +265,7 @@
         assertNotNull(connection);
         verify(connection, times(1))
                 .start(eq(false) /* useStrongBinding */,
-                        any(ChildProcessConnection.ServiceCallback.class));
+                        any(ChildProcessConnection.ServiceCallback.class), anyBoolean());
         assertTrue(mAllocator.anyConnectionAllocated());
 
         mTestConnectionFactory.simulateServiceProcessDying();
diff --git a/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java
new file mode 100644
index 0000000..ed85b1e
--- /dev/null
+++ b/content/public/android/junit/src/org/chromium/content/browser/ChildProcessConnectionTest.java
@@ -0,0 +1,92 @@
+// 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.content.browser;
+
+import android.content.ComponentName;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+/** Unit tests for ChildProcessConnection. */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ChildProcessConnectionTest {
+    @Before
+    public void setUp() {
+        // The tests run on only one thread. Pretend that is the launcher thread so LauncherThread
+        // asserts are not triggered.
+        LauncherThread.setCurrentThreadAsLauncherThread();
+    }
+
+    @After
+    public void tearDown() {
+        LauncherThread.setLauncherThreadAsLauncherThread();
+    }
+
+    private TestChildProcessConnection createTestConnection() {
+        String packageName = "org.chromium.test";
+        String serviceName = "TestService";
+        return new TestChildProcessConnection(new ComponentName(packageName, serviceName),
+                false /* bindAsExternalService */, null /* serviceBundle */,
+                null /* creationParams */);
+    }
+
+    @Test
+    public void testWatchdog() {
+        TestChildProcessConnection connection = createTestConnection();
+        connection.setPostOnServiceConnected(false);
+
+        connection.start(false /* useStrongBinding */, null /* serviceCallback */,
+                true /* retryOnTimeout */);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        Assert.assertTrue(connection.isInitialBindingBound());
+        Assert.assertFalse(connection.didOnServiceConnectedForTesting());
+
+        connection.setPostOnServiceConnected(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        Assert.assertTrue(connection.isInitialBindingBound());
+        Assert.assertTrue(connection.didOnServiceConnectedForTesting());
+    }
+
+    @Test
+    public void testWatchdogDisabled() {
+        TestChildProcessConnection connection = createTestConnection();
+        connection.setPostOnServiceConnected(false);
+
+        connection.start(false /* useStrongBinding */, null /* serviceCallback */,
+                false /* retryOnTimeout */);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        Assert.assertTrue(connection.isInitialBindingBound());
+        Assert.assertFalse(connection.didOnServiceConnectedForTesting());
+
+        connection.setPostOnServiceConnected(true);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        Assert.assertTrue(connection.isInitialBindingBound());
+        // No retry, so service is still not connected.
+        Assert.assertFalse(connection.didOnServiceConnectedForTesting());
+    }
+
+    @Test
+    public void testWatchdogCancelled() {
+        TestChildProcessConnection connection = createTestConnection();
+        connection.start(false /* useStrongBinding */, null /* serviceCallback */,
+                true /* retryOnTimeout */);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        Assert.assertTrue(connection.isInitialBindingBound());
+        Assert.assertTrue(connection.didOnServiceConnectedForTesting());
+
+        connection.setPostOnServiceConnected(false);
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        // Did not attempt to rebind.
+        Assert.assertTrue(connection.isInitialBindingBound());
+    }
+}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
index 2482297..106905d 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
@@ -57,6 +57,7 @@
             assert mConnection == null;
             mConnection = new TestChildProcessConnection(
                     serviceName, bindAsExternalService, serviceBundle, creationParams);
+            mConnection.setPostOnServiceConnected(false);
             return mConnection;
         }
 
@@ -132,7 +133,7 @@
         ChildProcessConnection connection =
                 mSpareConnection.getConnection(mWrongConnectionAllocator, mServiceCallback);
         assertNull(connection);
-        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        ShadowLooper.runUiThreadTasks();
         verify(mServiceCallback, times(0)).onChildStarted();
         verify(mServiceCallback, times(0)).onChildStartFailed();
         verify(mServiceCallback, times(0)).onChildProcessDied(any());
@@ -153,7 +154,7 @@
         // No more connections are available.
         assertTrue(mSpareConnection.isEmpty());
 
-        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        ShadowLooper.runUiThreadTasks();
         verify(mServiceCallback, times(1)).onChildStarted();
         verify(mServiceCallback, times(0)).onChildStartFailed();
     }
@@ -167,7 +168,7 @@
         ChildProcessConnection connection =
                 mSpareConnection.getConnection(mConnectionAllocator, mServiceCallback);
         assertNotNull(connection);
-        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        ShadowLooper.runUiThreadTasks();
         // No callbacks are called.
         verify(mServiceCallback, times(0)).onChildStarted();
         verify(mServiceCallback, times(0)).onChildStartFailed();
diff --git a/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java b/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
index 94f8dd8..0b150f2 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/TestChildProcessConnection.java
@@ -6,17 +6,49 @@
 
 import android.content.ComponentName;
 import android.os.Bundle;
+import android.os.IBinder;
 
 import org.chromium.base.process_launcher.ChildProcessCreationParams;
+import org.chromium.base.process_launcher.ICallbackInt;
+import org.chromium.base.process_launcher.IChildProcessService;
 
 /** An implementation of ChildProcessConnection that does not connect to a real service. */
 class TestChildProcessConnection extends ChildProcessConnection {
-    private static class MockChildServiceConnection
+    private static class MockServiceBinder extends IChildProcessService.Stub {
+        @Override
+        public boolean bindToCaller() {
+            return true;
+        }
+
+        @Override
+        public void setupConnection(Bundle args, ICallbackInt pidCallback, IBinder gpuCallback) {}
+
+        @Override
+        public void crashIntentionallyForTesting() {
+            throw new RuntimeException("crashIntentionallyForTesting");
+        }
+    }
+
+    private class MockChildServiceConnection
             implements ChildProcessConnection.ChildServiceConnection {
+        private final ChildProcessConnection mConnection;
         private boolean mBound;
 
+        MockChildServiceConnection(ChildProcessConnection connection) {
+            mConnection = connection;
+        }
+
         @Override
         public boolean bind() {
+            if (TestChildProcessConnection.this.mPostOnServiceConnected) {
+                LauncherThread.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        // TODO(boliu): implement a dummy service.
+                        mConnection.onServiceConnectedOnLauncherThread(new MockServiceBinder());
+                    }
+                });
+            }
             mBound = true;
             return true;
         }
@@ -35,6 +67,7 @@
     private int mPid;
     private boolean mConnected;
     private ServiceCallback mServiceCallback;
+    private boolean mPostOnServiceConnected;
 
     /**
      * Creates a mock binding corresponding to real ManagedChildProcessConnection after the
@@ -44,6 +77,7 @@
             Bundle serviceBundle, ChildProcessCreationParams creationParams) {
         super(null /* context */, serviceName, bindAsExternalService, serviceBundle,
                 creationParams);
+        mPostOnServiceConnected = true;
     }
 
     public void setPid(int pid) {
@@ -57,13 +91,14 @@
 
     @Override
     protected ChildServiceConnection createServiceConnection(int bindFlags) {
-        return new MockChildServiceConnection();
+        return new MockChildServiceConnection(this);
     }
 
     // We don't have a real service so we have to mock the connection status.
     @Override
-    public void start(boolean useStrongBinding, ServiceCallback serviceCallback) {
-        super.start(useStrongBinding, serviceCallback);
+    public void start(
+            boolean useStrongBinding, ServiceCallback serviceCallback, boolean retryOnTimeout) {
+        super.start(useStrongBinding, serviceCallback, retryOnTimeout);
         mConnected = true;
         mServiceCallback = serviceCallback;
     }
@@ -82,4 +117,8 @@
     public ServiceCallback getServiceCallback() {
         return mServiceCallback;
     }
+
+    public void setPostOnServiceConnected(boolean post) {
+        mPostOnServiceConnected = post;
+    }
 }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/androidoverlay/DialogOverlayCoreTest.java b/content/public/android/junit/src/org/chromium/content/browser/androidoverlay/DialogOverlayCoreTest.java
index 24a98615..8caf50a 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/androidoverlay/DialogOverlayCoreTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/androidoverlay/DialogOverlayCoreTest.java
@@ -14,6 +14,7 @@
 import android.os.IBinder;
 import android.view.Surface;
 import android.view.SurfaceHolder;
+import android.view.WindowManager;
 
 // TODO(liberato): prior to M, this was ...policy.impl.PhoneWindow
 import com.android.internal.policy.PhoneWindow;
@@ -44,6 +45,9 @@
 
     AndroidOverlayConfig mConfig = new AndroidOverlayConfig();
 
+    // Should we request a panel?
+    boolean mAsPanel;
+
     // DialogCore under test.
     DialogOverlayCore mCore;
 
@@ -68,11 +72,17 @@
         public MyPhoneWindowShadow() {}
 
         private SurfaceHolder.Callback2 mCallback;
+        private WindowManager.LayoutParams mLayoutParams;
 
         @Implementation
         public void takeSurface(SurfaceHolder.Callback2 callback) {
             mCallback = callback;
         }
+
+        @Implementation
+        public void setAttributes(WindowManager.LayoutParams layoutParams) {
+            mLayoutParams = layoutParams;
+        }
     }
 
     /**
@@ -102,9 +112,11 @@
         mConfig.rect.y = 1;
         mConfig.rect.width = 2;
         mConfig.rect.height = 3;
+    }
 
+    public void createOverlay() {
         mCore = new DialogOverlayCore();
-        mCore.initialize(mActivity, mConfig, mHost);
+        mCore.initialize(mActivity, mConfig, mHost, mAsPanel);
         mDialog = mCore.getDialog();
 
         // Nothing should be called yet.
@@ -127,6 +139,11 @@
         return ((MyPhoneWindowShadow) Shadows.shadowOf(mDialog.getWindow())).mCallback;
     }
 
+    // Return the LayoutPararms that was most recently provided to the dialog.
+    WindowManager.LayoutParams layoutParams() {
+        return ((MyPhoneWindowShadow) Shadows.shadowOf(mDialog.getWindow())).mLayoutParams;
+    }
+
     /**
      * Host impl that counts calls to it.
      */
@@ -205,6 +222,7 @@
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testReleaseImmediately() {
         // Release the overlay.  |mCore| shouldn't notify us, since we released it.
+        createOverlay();
         mCore.release();
         checkOverlayDidntCall();
         checkDialogIsNotShown();
@@ -214,6 +232,7 @@
     @Test
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testTokenThenRelease() {
+        createOverlay();
         mCore.onWindowToken(mWindowToken);
         checkDialogIsShown();
 
@@ -229,6 +248,7 @@
     @Test
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testSurfaceThenRelease() {
+        createOverlay();
         sendTokenAndSurface();
 
         mCore.release();
@@ -241,6 +261,7 @@
     @Test
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testSurfaceThenDestroy() {
+        createOverlay();
         sendTokenAndSurface();
 
         // Destroy the surface.
@@ -258,6 +279,7 @@
     @Test
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testChangeWindowToken() {
+        createOverlay();
         sendTokenAndSurface();
 
         // Change the window token.
@@ -270,6 +292,7 @@
     @Test
     @Config(shadows = {MyPhoneWindowShadow.class})
     public void testLoseWindowToken() {
+        createOverlay();
         sendTokenAndSurface();
 
         // Remove the window token.
@@ -277,4 +300,28 @@
 
         checkOverlayWasDestroyed();
     }
+
+    // Test that the layout params reflect TYPE_APPLICATION_MEDIA, and that it its geometry matches
+    // what we requested.
+    @Test
+    @Config(shadows = {MyPhoneWindowShadow.class})
+    public void testOverlayTypeAndGeometry() {
+        createOverlay();
+        mCore.onWindowToken(mWindowToken);
+        assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA, layoutParams().type);
+        assertEquals(mConfig.rect.x, layoutParams().x);
+        assertEquals(mConfig.rect.y, layoutParams().y);
+        assertEquals(mConfig.rect.width, layoutParams().width);
+        assertEquals(mConfig.rect.height, layoutParams().height);
+    }
+
+    // Test that the layout params reflect TYPE_APPLICATION_PANEL when we request it.
+    @Test
+    @Config(shadows = {MyPhoneWindowShadow.class})
+    public void testOverlayAsPanel() {
+        mAsPanel = true;
+        createOverlay();
+        mCore.onWindowToken(mWindowToken);
+        assertEquals(layoutParams().type, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
+    }
 }
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_features.cc b/content/public/common/content_features.cc
index 49e3a66..0b6d983 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -241,6 +241,10 @@
     "RequireSecureOriginsForPepperMediaRequests",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Loading Dispatcher v0 support with ResourceLoadScheduler (crbug.com/729954).
+const base::Feature kResourceLoadScheduler{"ResourceLoadScheduler",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Scrolls to compensate for layout movements (bit.ly/scroll-anchoring).
 const base::Feature kScrollAnchoring{"ScrollAnchoring",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 8f3eb65..a1c84aad 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -65,6 +65,7 @@
 CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling;
 CONTENT_EXPORT extern const base::Feature
     kRequireSecureOriginsForPepperMediaRequests;
+CONTENT_EXPORT extern const base::Feature kResourceLoadScheduler;
 CONTENT_EXPORT extern const base::Feature kScrollAnchoring;
 CONTENT_EXPORT extern const base::Feature kServiceWorkerNavigationPreload;
 CONTENT_EXPORT extern const base::Feature kServiceWorkerScriptStreaming;
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/renderer/render_thread.h b/content/public/renderer/render_thread.h
index d5d13295..3ffc7bc 100644
--- a/content/public/renderer/render_thread.h
+++ b/content/public/renderer/render_thread.h
@@ -22,10 +22,6 @@
 class WaitableEvent;
 }
 
-namespace cc {
-class SharedBitmapManager;
-}
-
 namespace IPC {
 class MessageFilter;
 class SyncChannel;
@@ -36,6 +32,10 @@
 class Extension;
 }
 
+namespace viz {
+class SharedBitmapManager;
+}
+
 namespace content {
 
 class RenderThreadObserver;
@@ -77,7 +77,7 @@
   virtual std::unique_ptr<base::SharedMemory> HostAllocateSharedMemoryBuffer(
       size_t buffer_size) = 0;
 
-  virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0;
+  virtual viz::SharedBitmapManager* GetSharedBitmapManager() = 0;
 
   // Registers the given V8 extension with WebKit.
   virtual void RegisterExtension(v8::Extension* extension) = 0;
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/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 886a353..8d49131 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -195,7 +195,7 @@
   return std::unique_ptr<base::SharedMemory>(shared_buf.release());
 }
 
-cc::SharedBitmapManager* MockRenderThread::GetSharedBitmapManager() {
+viz::SharedBitmapManager* MockRenderThread::GetSharedBitmapManager() {
   return &shared_bitmap_manager_;
 }
 
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 701a2c8f..076e6fe 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -71,7 +71,7 @@
   void RecordComputedAction(const std::string& action) override;
   std::unique_ptr<base::SharedMemory> HostAllocateSharedMemoryBuffer(
       size_t buffer_size) override;
-  cc::SharedBitmapManager* GetSharedBitmapManager() override;
+  viz::SharedBitmapManager* GetSharedBitmapManager() override;
   void RegisterExtension(v8::Extension* extension) override;
   void ScheduleIdleHandler(int64_t initial_delay_ms) override;
   void IdleHandler() override;
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h
index f3f802f..df6c686 100644
--- a/content/public/test/web_contents_tester.h
+++ b/content/public/test/web_contents_tester.h
@@ -154,6 +154,9 @@
 
   // Sets the return value of GetLastCommittedUrl() of TestWebContents.
   virtual void SetLastCommittedURL(const GURL& url) = 0;
+
+  // Override WasRecentlyAudible for testing.
+  virtual void SetWasRecentlyAudible(bool audible) = 0;
 };
 
 }  // namespace content
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index 93126e84..c3ef7730 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -9,6 +9,8 @@
   "+components/url_formatter",
   "+components/variations",
   "+components/viz/client",
+  "+components/viz/common/quads",
+  "+components/viz/common/resources",
 
   "+cc/blink",
   "+content/public/child",
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index ad3f85ab..6fe3d64eb 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -109,7 +109,7 @@
     scoped_refptr<cc::ContextProvider> context_provider,
     scoped_refptr<cc::ContextProvider> worker_context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-    cc::SharedBitmapManager* shared_bitmap_manager,
+    viz::SharedBitmapManager* shared_bitmap_manager,
     int routing_id,
     uint32_t layer_tree_frame_sink_id,
     std::unique_ptr<cc::BeginFrameSource> begin_frame_source,
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.h b/content/renderer/android/synchronous_layer_tree_frame_sink.h
index 9b66c5b..de4632d 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.h
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.h
@@ -71,7 +71,7 @@
       scoped_refptr<cc::ContextProvider> context_provider,
       scoped_refptr<cc::ContextProvider> worker_context_provider,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      cc::SharedBitmapManager* shared_bitmap_manager,
+      viz::SharedBitmapManager* shared_bitmap_manager,
       int routing_id,
       uint32_t layer_tree_frame_sink_id,
       std::unique_ptr<cc::BeginFrameSource> begin_frame_source,
@@ -125,7 +125,7 @@
   const int routing_id_;
   const uint32_t layer_tree_frame_sink_id_;
   SynchronousCompositorRegistry* const registry_;         // Not owned.
-  cc::SharedBitmapManager* const shared_bitmap_manager_;  // Not owned.
+  viz::SharedBitmapManager* const shared_bitmap_manager_;  // Not owned.
   IPC::Sender* const sender_;                             // Not owned.
 
   // Not owned.
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..3a48e80 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -12,7 +12,9 @@
 #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/public/common/service_names.mojom.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
@@ -23,6 +25,7 @@
 #include "media/gpu/ipc/common/media_messages.h"
 #include "media/video/video_decode_accelerator.h"
 #include "media/video/video_encode_accelerator.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
 
 namespace content {
@@ -51,14 +54,15 @@
     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,
-    bool enable_video_accelerator) {
+    const viz::BufferToTextureTargetMap& image_texture_targets,
+    bool enable_video_accelerator,
+    media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea) {
   RecordContextProviderPhaseUmaEnum(
       ContextProviderPhase::CONTEXT_PROVIDER_ACQUIRED);
   return base::WrapUnique(new GpuVideoAcceleratorFactoriesImpl(
       std::move(gpu_channel_host), main_thread_task_runner, task_runner,
       context_provider, enable_gpu_memory_buffer_video_frames,
-      image_texture_targets, enable_video_accelerator));
+      image_texture_targets, enable_video_accelerator, std::move(unbound_vea)));
 }
 
 GpuVideoAcceleratorFactoriesImpl::GpuVideoAcceleratorFactoriesImpl(
@@ -67,8 +71,9 @@
     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,
-    bool enable_video_accelerator)
+    const viz::BufferToTextureTargetMap& image_texture_targets,
+    bool enable_video_accelerator,
+    media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea)
     : main_thread_task_runner_(main_thread_task_runner),
       task_runner_(task_runner),
       gpu_channel_host_(std::move(gpu_channel_host)),
@@ -80,6 +85,7 @@
       video_accelerator_enabled_(enable_video_accelerator),
       gpu_memory_buffer_manager_(
           RenderThreadImpl::current()->GetGpuMemoryBufferManager()),
+      unbound_vea_(std::move(unbound_vea)),
       thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {
   DCHECK(main_thread_task_runner_);
   DCHECK(gpu_channel_host_);
@@ -152,6 +158,13 @@
   if (CheckContextLost())
     return nullptr;
 
+  media::mojom::VideoEncodeAcceleratorPtr vea;
+  vea.Bind(std::move(unbound_vea_));
+  if (vea) {
+    // TODO(mcasas): Create a mojom::MojoVideoEncodeAcceleratorHost
+    // implementation and use it, https://crbug.com/736517
+  }
+
   return std::unique_ptr<media::VideoEncodeAccelerator>(
       new media::GpuVideoEncodeAcceleratorHost(
           context_provider_->GetCommandBufferProxy()));
@@ -262,7 +275,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..3a3a52fc 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
@@ -17,9 +17,10 @@
 #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/mojo/interfaces/video_encode_accelerator.mojom.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -54,8 +55,9 @@
       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,
-      bool enable_video_accelerator);
+      const viz::BufferToTextureTargetMap& image_texture_targets,
+      bool enable_video_accelerator,
+      media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea);
 
   // media::GpuVideoAcceleratorFactories implementation.
   bool IsGpuVideoAcceleratorEnabled() override;
@@ -109,8 +111,9 @@
       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,
-      bool enable_video_accelerator);
+      const viz::BufferToTextureTargetMap& image_texture_targets,
+      bool enable_video_accelerator,
+      media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea);
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -127,12 +130,14 @@
 
   // 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_;
 
   gpu::GpuMemoryBufferManager* const gpu_memory_buffer_manager_;
 
+  media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea_;
+
   // For sending requests to allocate shared memory in the Browser process.
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
 
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/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
index d8e505b..a9cdcec 100644
--- a/content/renderer/pepper/pepper_compositor_host.cc
+++ b/content/renderer/pepper/pepper_compositor_host.cc
@@ -192,7 +192,7 @@
 void PepperCompositorHost::ImageReleased(
     int32_t id,
     std::unique_ptr<base::SharedMemory> shared_memory,
-    std::unique_ptr<cc::SharedBitmap> bitmap,
+    std::unique_ptr<viz::SharedBitmap> bitmap,
     const gpu::SyncToken& sync_token,
     bool is_lost) {
   bitmap.reset();
@@ -314,7 +314,7 @@
       DCHECK_EQ(rv, PP_TRUE);
       DCHECK_EQ(desc.stride, desc.size.width * 4);
       DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
-      std::unique_ptr<cc::SharedBitmap> bitmap =
+      std::unique_ptr<viz::SharedBitmap> bitmap =
           RenderThreadImpl::current()
               ->shared_bitmap_manager()
               ->GetBitmapForSharedMemory(image_shm.get());
diff --git a/content/renderer/pepper/pepper_compositor_host.h b/content/renderer/pepper/pepper_compositor_host.h
index 0163a74..b2bc049 100644
--- a/content/renderer/pepper/pepper_compositor_host.h
+++ b/content/renderer/pepper/pepper_compositor_host.h
@@ -22,13 +22,16 @@
 
 namespace cc {
 class Layer;
-class SharedBitmap;
 }  // namespace cc
 
 namespace gpu {
 struct SyncToken;
 }  // namespace gpu
 
+namespace viz {
+class SharedBitmap;
+}
+
 namespace content {
 
 class PepperPluginInstanceImpl;
@@ -59,7 +62,7 @@
  private:
   void ImageReleased(int32_t id,
                      std::unique_ptr<base::SharedMemory> shared_memory,
-                     std::unique_ptr<cc::SharedBitmap> bitmap,
+                     std::unique_ptr<viz::SharedBitmap> bitmap,
                      const gpu::SyncToken& sync_token,
                      bool is_lost);
   void ResourceReleased(int32_t id,
diff --git a/content/renderer/pepper/pepper_graphics_2d_host.cc b/content/renderer/pepper/pepper_graphics_2d_host.cc
index a411e2f..435c55d0 100644
--- a/content/renderer/pepper/pepper_graphics_2d_host.cc
+++ b/content/renderer/pepper/pepper_graphics_2d_host.cc
@@ -15,9 +15,9 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "cc/paint/paint_flags.h"
-#include "cc/resources/shared_bitmap.h"
 #include "cc/resources/texture_mailbox.h"
 #include "components/viz/client/client_shared_bitmap_manager.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "content/renderer/pepper/gfx_conversion.h"
@@ -546,7 +546,7 @@
 }
 
 void PepperGraphics2DHost::ReleaseCallback(
-    std::unique_ptr<cc::SharedBitmap> bitmap,
+    std::unique_ptr<viz::SharedBitmap> bitmap,
     const gfx::Size& bitmap_size,
     const gpu::SyncToken& sync_token,
     bool lost_resource) {
@@ -565,7 +565,7 @@
     return false;
   // TODO(jbauman): Send image_data_ through mailbox to avoid copy.
   gfx::Size pixel_image_size(image_data_->width(), image_data_->height());
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap;
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap;
   if (cached_bitmap_) {
     if (cached_bitmap_size_ == pixel_image_size)
       shared_bitmap = std::move(cached_bitmap_);
@@ -580,9 +580,8 @@
   if (!shared_bitmap)
     return false;
   void* src = image_data_->Map();
-  memcpy(shared_bitmap->pixels(),
-         src,
-         cc::SharedBitmap::CheckedSizeInBytes(pixel_image_size));
+  memcpy(shared_bitmap->pixels(), src,
+         viz::SharedBitmap::CheckedSizeInBytes(pixel_image_size));
   image_data_->Unmap();
 
   *mailbox = cc::TextureMailbox(shared_bitmap.get(), pixel_image_size);
diff --git a/content/renderer/pepper/pepper_graphics_2d_host.h b/content/renderer/pepper/pepper_graphics_2d_host.h
index 97a39ef0..ce8355d7 100644
--- a/content/renderer/pepper/pepper_graphics_2d_host.h
+++ b/content/renderer/pepper/pepper_graphics_2d_host.h
@@ -22,7 +22,6 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
-class SharedBitmap;
 class SingleReleaseCallback;
 class TextureMailbox;
 }
@@ -35,6 +34,10 @@
 struct SyncToken;
 }
 
+namespace viz {
+class SharedBitmap;
+}
+
 namespace content {
 
 class PepperPluginInstanceImpl;
@@ -171,7 +174,7 @@
                                      gfx::Rect* op_rect,
                                      gfx::Point* delta);
 
-  void ReleaseCallback(std::unique_ptr<cc::SharedBitmap> bitmap,
+  void ReleaseCallback(std::unique_ptr<viz::SharedBitmap> bitmap,
                        const gfx::Size& bitmap_size,
                        const gpu::SyncToken& sync_token,
                        bool lost_resource);
@@ -216,7 +219,7 @@
 
   // This is a bitmap that was recently released by the compositor and may be
   // used to transfer bytes to the compositor again.
-  std::unique_ptr<cc::SharedBitmap> cached_bitmap_;
+  std::unique_ptr<viz::SharedBitmap> cached_bitmap_;
   gfx::Size cached_bitmap_size_;
 
   friend class PepperGraphics2DHostTest;
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..6ca8796 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;
@@ -1319,7 +1319,7 @@
   return ChildThreadImpl::AllocateSharedMemory(size);
 }
 
-cc::SharedBitmapManager* RenderThreadImpl::GetSharedBitmapManager() {
+viz::SharedBitmapManager* RenderThreadImpl::GetSharedBitmapManager() {
   return shared_bitmap_manager();
 }
 
@@ -1464,11 +1464,15 @@
       cmd_line->HasSwitch(switches::kEnableGpuMemoryBufferVideoFrames);
 #endif
 
+  media::mojom::VideoEncodeAcceleratorPtr vea;
+  gpu_->CreateVideoEncodeAccelerator(mojo::MakeRequest(&vea));
+  media::mojom::VideoEncodeAcceleratorPtrInfo unbound_vea = vea.PassInterface();
+
   gpu_factories_.push_back(GpuVideoAcceleratorFactoriesImpl::Create(
       std::move(gpu_channel_host), base::ThreadTaskRunnerHandle::Get(),
       media_task_runner, std::move(media_context_provider),
       enable_gpu_memory_buffer_video_frames, buffer_to_texture_target_map_,
-      enable_video_accelerator));
+      enable_video_accelerator, std::move(unbound_vea)));
   return gpu_factories_.back().get();
 }
 
@@ -1605,7 +1609,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..256cdae 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -214,7 +214,7 @@
       ResourceDispatcherDelegate* delegate) override;
   std::unique_ptr<base::SharedMemory> HostAllocateSharedMemoryBuffer(
       size_t buffer_size) override;
-  cc::SharedBitmapManager* GetSharedBitmapManager() override;
+  viz::SharedBitmapManager* GetSharedBitmapManager() override;
   void RegisterExtension(v8::Extension* extension) override;
   void ScheduleIdleHandler(int64_t initial_delay_ms) override;
   void IdleHandler() override;
@@ -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/render_view_impl.cc b/content/renderer/render_view_impl.cc
index bc40880..0219970 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2346,9 +2346,9 @@
     case TAP_MULTIPLE_TARGETS_STRATEGY_POPUP: {
       gfx::Size canvas_size =
           gfx::ScaleToCeiledSize(zoom_rect.size(), new_total_scale);
-      cc::SharedBitmapManager* manager =
+      viz::SharedBitmapManager* manager =
           RenderThreadImpl::current()->shared_bitmap_manager();
-      std::unique_ptr<cc::SharedBitmap> shared_bitmap =
+      std::unique_ptr<viz::SharedBitmap> shared_bitmap =
           manager->AllocateSharedBitmap(canvas_size);
       CHECK(!!shared_bitmap);
       {
@@ -2381,7 +2381,7 @@
       Send(new ViewHostMsg_ShowDisambiguationPopup(
           GetRoutingID(), physical_window_zoom_rect, canvas_size,
           shared_bitmap->id()));
-      cc::SharedBitmapId id = shared_bitmap->id();
+      viz::SharedBitmapId id = shared_bitmap->id();
       disambiguation_bitmaps_[id] = shared_bitmap.release();
       handled = true;
       break;
@@ -2479,7 +2479,7 @@
 }
 
 void RenderViewImpl::OnReleaseDisambiguationPopupBitmap(
-    const cc::SharedBitmapId& id) {
+    const viz::SharedBitmapId& id) {
   BitmapMap::iterator it = disambiguation_bitmaps_.find(id);
   DCHECK(it != disambiguation_bitmaps_.end());
   delete it->second;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index ded94ab..cb7f83d2 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -24,7 +24,7 @@
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "cc/input/browser_controls_state.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "content/common/content_export.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/navigation_gesture.h"
@@ -524,7 +524,7 @@
   void OnPluginActionAt(const gfx::Point& location,
                         const blink::WebPluginAction& action);
   void OnMoveOrResizeStarted();
-  void OnReleaseDisambiguationPopupBitmap(const cc::SharedBitmapId& id);
+  void OnReleaseDisambiguationPopupBitmap(const viz::SharedBitmapId& id);
   void OnResolveTapDisambiguation(double timestamp_seconds,
                                   gfx::Point tap_viewport_offset,
                                   bool is_long_press);
@@ -797,7 +797,7 @@
   // constructors call the AddObservers method of RenderViewImpl.
   std::unique_ptr<StatsCollectionObserver> stats_collection_observer_;
 
-  typedef std::map<cc::SharedBitmapId, cc::SharedBitmap*> BitmapMap;
+  typedef std::map<viz::SharedBitmapId, viz::SharedBitmap*> BitmapMap;
   BitmapMap disambiguation_bitmaps_;
 
   std::unique_ptr<IdleUserDetector> idle_user_detector_;
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 8382852..5bce20b 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1095,7 +1095,7 @@
 
 //------------------------------------------------------------------------------
 
-std::unique_ptr<cc::SharedBitmap>
+std::unique_ptr<viz::SharedBitmap>
 RendererBlinkPlatformImpl::AllocateSharedBitmap(const blink::WebSize& size) {
   return shared_bitmap_manager_
       ->AllocateSharedBitmap(gfx::Size(size.width, size.height));
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index c5614a1..33f26240 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -193,7 +193,7 @@
   std::unique_ptr<blink::WebGraphicsContext3DProvider>
   CreateSharedOffscreenGraphicsContext3DProvider() override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
-  std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+  std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
       const blink::WebSize& size) override;
   blink::WebCompositorSupport* CompositorSupport() override;
   blink::WebString ConvertIDNToUnicode(const blink::WebString& host) override;
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/shell/DEPS b/content/shell/DEPS
index 7081670b..6d65a6a 100644
--- a/content/shell/DEPS
+++ b/content/shell/DEPS
@@ -29,6 +29,7 @@
   "+components/crash",
   "+components/url_formatter",
   "+components/network_session_configurator/common",
+  "+components/viz/common/resources",
 ]
 
 specific_include_rules = {
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index 4a6ef125..a612ebb 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -723,7 +723,7 @@
   Send(new LayoutTestHostMsg_ResetPermissions(routing_id()));
 }
 
-cc::SharedBitmapManager* BlinkTestRunner::GetSharedBitmapManager() {
+viz::SharedBitmapManager* BlinkTestRunner::GetSharedBitmapManager() {
   return RenderThread::Get()->GetSharedBitmapManager();
 }
 
diff --git a/content/shell/renderer/layout_test/blink_test_runner.h b/content/shell/renderer/layout_test/blink_test_runner.h
index c3b497aa..22c3f718 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.h
+++ b/content/shell/renderer/layout_test/blink_test_runner.h
@@ -150,7 +150,7 @@
       blink::WebMediaStream* stream) override;
   bool AddMediaStreamAudioSourceAndTrack(
       blink::WebMediaStream* stream) override;
-  cc::SharedBitmapManager* GetSharedBitmapManager() override;
+  viz::SharedBitmapManager* GetSharedBitmapManager() override;
   void DispatchBeforeInstallPromptEvent(
       const std::vector<std::string>& event_platforms,
       const base::Callback<void(bool)>& callback) override;
diff --git a/content/shell/test_runner/test_plugin.cc b/content/shell/test_runner/test_plugin.cc
index 905a92c9..f0850bb 100644
--- a/content/shell/test_runner/test_plugin.cc
+++ b/content/shell/test_runner/test_plugin.cc
@@ -16,7 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "cc/blink/web_layer_impl.h"
 #include "cc/layers/texture_layer.h"
-#include "cc/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "content/shell/test_runner/web_test_delegate.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/WebKit/public/platform/Platform.h"
@@ -268,7 +268,7 @@
     gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
     texture_mailbox_ = cc::TextureMailbox(mailbox, sync_token, GL_TEXTURE_2D);
   } else {
-    std::unique_ptr<cc::SharedBitmap> bitmap =
+    std::unique_ptr<viz::SharedBitmap> bitmap =
         delegate_->GetSharedBitmapManager()->AllocateSharedBitmap(
             gfx::Rect(rect_).size());
     if (!bitmap) {
@@ -292,7 +292,7 @@
 static void IgnoreReleaseCallback(const gpu::SyncToken& sync_token, bool lost) {
 }
 
-static void ReleaseSharedMemory(std::unique_ptr<cc::SharedBitmap> bitmap,
+static void ReleaseSharedMemory(std::unique_ptr<viz::SharedBitmap> bitmap,
                                 const gpu::SyncToken& sync_token,
                                 bool lost) {}
 
diff --git a/content/shell/test_runner/test_plugin.h b/content/shell/test_runner/test_plugin.h
index 8e663ac..5a209c2 100644
--- a/content/shell/test_runner/test_plugin.h
+++ b/content/shell/test_runner/test_plugin.h
@@ -151,7 +151,7 @@
   gpu::gles2::GLES2Interface* gl_;
   GLuint color_texture_;
   cc::TextureMailbox texture_mailbox_;
-  std::unique_ptr<cc::SharedBitmap> shared_bitmap_;
+  std::unique_ptr<viz::SharedBitmap> shared_bitmap_;
   bool mailbox_changed_;
   GLuint framebuffer_;
   Scene scene_;
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h
index 58f0fb0..344018e3 100644
--- a/content/shell/test_runner/web_test_delegate.h
+++ b/content/shell/test_runner/web_test_delegate.h
@@ -34,15 +34,15 @@
 class WebView;
 }
 
-namespace cc {
-class SharedBitmapManager;
-}
-
 namespace device {
 class MotionData;
 class OrientationData;
 }
 
+namespace viz {
+class SharedBitmapManager;
+}
+
 namespace test_runner {
 
 class GamepadController;
@@ -268,7 +268,7 @@
   virtual bool AddMediaStreamAudioSourceAndTrack(
       blink::WebMediaStream* stream) = 0;
 
-  virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0;
+  virtual viz::SharedBitmapManager* GetSharedBitmapManager() = 0;
 
   // Causes the beforeinstallprompt event to be sent to the renderer.
   // |event_platforms| are the platforms to be sent with the event. Once the
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 d3b56104..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/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index d549c3e2..c19d608 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -203,7 +203,7 @@
   return blink::WebString::FromUTF8("test_runner/0.0.0.0");
 }
 
-std::unique_ptr<cc::SharedBitmap>
+std::unique_ptr<viz::SharedBitmap>
 TestBlinkWebUnitTestSupport::AllocateSharedBitmap(const blink::WebSize& size) {
   return shared_bitmap_manager_
       ->AllocateSharedBitmap(gfx::Size(size.width, size.height));
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h
index 7ebb831b..556242d76 100644
--- a/content/test/test_blink_web_unit_test_support.h
+++ b/content/test/test_blink_web_unit_test_support.h
@@ -66,7 +66,7 @@
 
   blink::WebThread* CurrentThread() override;
 
-  std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+  std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
       const blink::WebSize& size) override;
 
   void GetPluginList(bool refresh,
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index f495cd8..e38edb33 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -429,4 +429,8 @@
   save_frame_headers_ = headers;
 }
 
+void TestWebContents::SetWasRecentlyAudible(bool audible) {
+  audio_stream_monitor()->set_was_recently_audible_for_testing(audible);
+}
+
 }  // namespace content
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index c8ca044..2359bcc 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -92,6 +92,7 @@
       const std::vector<SkBitmap>& bitmaps,
       const std::vector<gfx::Size>& original_bitmap_sizes) override;
   void SetLastCommittedURL(const GURL& url) override;
+  void SetWasRecentlyAudible(bool audible) override;
 
   // True if a cross-site navigation is pending.
   bool CrossProcessNavigationPending();
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/BUILD.gn b/device/geolocation/public/interfaces/BUILD.gn
index 0ae7cc7..44b518f 100644
--- a/device/geolocation/public/interfaces/BUILD.gn
+++ b/device/geolocation/public/interfaces/BUILD.gn
@@ -9,7 +9,4 @@
     "geolocation.mojom",
     "geoposition.mojom",
   ]
-
-  # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
 }
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/docs/ios/build_instructions.md b/docs/ios/build_instructions.md
index 6395b7b1..3a70ff0 100644
--- a/docs/ios/build_instructions.md
+++ b/docs/ios/build_instructions.md
@@ -185,9 +185,8 @@
 In addition to that, then you'll need one additional provisioning profile for
 the XCTest module too. This module bundle identifier depends on whether the
 gn variable `ios_automatically_manage_certs` is set to true or false. If set
-to true, then `${prefix}.test.gtest.generic-unit-test.generic-unit-test-module`
-will be used, otherwise it will match the following pattern:
-`${prefix}.test.${test-suite-name}.${test-suite-name}-module`.
+to true, then `${prefix}.gtest.generic-unit-test-module` will be used, otherwise
+it will match the pattern: `${prefix}.gtest.${test-suite-name}-module`.
 
 ### Other applications
 
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/common/manifest_handlers/webview_info.cc b/extensions/common/manifest_handlers/webview_info.cc
index 57a5aa01..cbb913d0 100644
--- a/extensions/common/manifest_handlers/webview_info.cc
+++ b/extensions/common/manifest_handlers/webview_info.cc
@@ -86,6 +86,22 @@
   return false;
 }
 
+// static
+bool WebviewInfo::HasWebviewAccessibleResources(
+    const Extension& extension,
+    const std::string& partition_id) {
+  const WebviewInfo* webview_info = static_cast<const WebviewInfo*>(
+      extension.GetManifestData(keys::kWebviewAccessibleResources));
+  if (!webview_info)
+    return false;
+
+  for (const auto& item : webview_info->partition_items_) {
+    if (item->Matches(partition_id))
+      return true;
+  }
+  return false;
+}
+
 void WebviewInfo::AddPartitionItem(std::unique_ptr<PartitionItem> item) {
   partition_items_.push_back(std::move(item));
 }
diff --git a/extensions/common/manifest_handlers/webview_info.h b/extensions/common/manifest_handlers/webview_info.h
index 5deb897..58feb6e 100644
--- a/extensions/common/manifest_handlers/webview_info.h
+++ b/extensions/common/manifest_handlers/webview_info.h
@@ -27,6 +27,10 @@
   static bool IsResourceWebviewAccessible(const Extension* extension,
                                           const std::string& partition_id,
                                           const std::string& relative_path);
+  // Returns true if the given |extension| has any webview accessible
+  // resources in the given |partition_id|.
+  static bool HasWebviewAccessibleResources(const Extension& extension,
+                                            const std::string& partition_id);
 
   // Define out of line constructor/destructor to please Clang.
   explicit WebviewInfo(const std::string& extension_id);
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/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 67d8bea..12c487d 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -1073,6 +1073,8 @@
       extension->permissions_data()->SetPolicyHostRestrictions(
           param.policy_blocked_hosts, param.policy_allowed_hosts);
     }
+
+    ExtensionsRendererClient::Get()->OnExtensionLoaded(*extension);
   }
 
   // Update the available bindings for all contexts. These may have changed if
@@ -1174,6 +1176,8 @@
     return;
   }
 
+  ExtensionsRendererClient::Get()->OnExtensionUnloaded(id);
+
   active_extension_ids_.erase(id);
 
   script_injection_manager_->OnExtensionUnloaded(id);
diff --git a/extensions/renderer/extensions_renderer_client.h b/extensions/renderer/extensions_renderer_client.h
index 8ead04c..2ef7246 100644
--- a/extensions/renderer/extensions_renderer_client.h
+++ b/extensions/renderer/extensions_renderer_client.h
@@ -5,7 +5,10 @@
 #ifndef EXTENSIONS_RENDERER_EXTENSIONS_RENDERER_CLIENT_H_
 #define EXTENSIONS_RENDERER_EXTENSIONS_RENDERER_CLIENT_H_
 
+#include "extensions/common/extension_id.h"
+
 namespace extensions {
+class Extension;
 class Dispatcher;
 
 // Interface to allow the extensions module to make render-process-specific
@@ -29,6 +32,11 @@
   // Returns the associated Dispatcher.
   virtual Dispatcher* GetDispatcher() = 0;
 
+  // Notifies the client when an extension is added or removed.
+  // TODO(devlin): Make a RendererExtensionRegistryObserver?
+  virtual void OnExtensionLoaded(const Extension& extension) {}
+  virtual void OnExtensionUnloaded(const ExtensionId& extension) {}
+
   // Returns the single instance of |this|.
   static ExtensionsRendererClient* Get();
 
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/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index 5e3181e4..47cecdf4 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
@@ -458,7 +459,11 @@
   }
 };
 
+#if defined(OS_WIN)
+DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeletePageTest);
+#else
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeletePageTest);
+#endif
 
 class TargetDomainCreateAndDeleteBrowserContextTest
     : public HeadlessAsyncDevTooledBrowserTest {
@@ -526,7 +531,12 @@
   std::string browser_context_id_;
 };
 
+#if defined(OS_WIN)
+DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(
+    TargetDomainCreateAndDeleteBrowserContextTest);
+#else
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeleteBrowserContextTest);
+#endif
 
 class TargetDomainDisposeContextFailsIfInUse
     : public HeadlessAsyncDevTooledBrowserTest {
@@ -602,7 +612,12 @@
   std::string page_id_;
 };
 
+#if defined(OS_WIN)
+DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(
+    TargetDomainDisposeContextFailsIfInUse);
+#else
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainDisposeContextFailsIfInUse);
+#endif
 
 class TargetDomainCreateTwoContexts : public HeadlessAsyncDevTooledBrowserTest,
                                       public target::ExperimentalObserver,
@@ -874,7 +889,11 @@
   int context_closed_count_ = 0;
 };
 
+#if defined(OS_WIN)
+DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateTwoContexts);
+#else
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateTwoContexts);
+#endif
 
 class HeadlessDevToolsNavigationControlTest
     : public HeadlessAsyncDevTooledBrowserTest,
diff --git a/headless/test/headless_browser_test.h b/headless/test/headless_browser_test.h
index b5ef877..5181ba42 100644
--- a/headless/test/headless_browser_test.h
+++ b/headless/test/headless_browser_test.h
@@ -94,6 +94,7 @@
   DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserTest);
 };
 
+// TODO(eseckler): Make macro more sheriff-friendly.
 #define HEADLESS_ASYNC_DEVTOOLED_TEST_F(TEST_FIXTURE_NAME)               \
   IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \
   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
@@ -102,6 +103,18 @@
   IN_PROC_BROWSER_TEST_P(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \
   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
 
+#define DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(TEST_FIXTURE_NAME)  \
+  IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, DISABLED_RunAsyncTest) { \
+    RunTest();                                                       \
+  }                                                                  \
+  class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_P(TEST_FIXTURE_NAME)  \
+  IN_PROC_BROWSER_TEST_P(TEST_FIXTURE_NAME, DISABLED_RunAsyncTest) { \
+    RunTest();                                                       \
+  }                                                                  \
+  class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
+
 // Base class for tests that require access to a DevToolsClient. Subclasses
 // should override the RunDevTooledTest() method, which is called asynchronously
 // when the DevToolsClient is ready.
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json
index b55089c..a2bee3d 100644
--- a/ios/build/bots/tests/eg_tests.json
+++ b/ios/build/bots/tests/eg_tests.json
@@ -3,6 +3,10 @@
     {
       "app": "ios_chrome_integration_egtests",
       "xctest": true
+    },
+    {
+      "app": "ios_web_shell_egtests",
+      "xctest": true
     }
   ]
 }
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 1d9a7d8..1bafa1c 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -100,6 +100,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_interaction_controller.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
 #import "ios/chrome/browser/ui/chrome_web_view_factory.h"
+#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 0473879..d8437f1 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -544,7 +544,7 @@
         Save Image
       </message>
       <message name="IDS_IOS_CONTENT_SUGGESTIONS_ACCESSIBILITY_LABEL_SUGGESTION" desc="The accessibility label of a suggestion. Summarizes fields in the reading list entry (title, publisher informations, status and informations). Read by Text-to-Speech.">
-        <ph name="TITLE"><ex>Learn about the new Chromium Projects</ex>$1</ph>, <ph name="PUBLISHER_INFORMATION"><ex>The Chromium organization</ex>$2</ph>, <ph name="PUBLICATION_DATE"><ex>January 1 2017</ex>$3</ph>, <ph name="STATE"><ex>Available offline</ex>$4</ph>, <ph name="ADDITIONAL_INFORMATIONS"><ex>The Chromium projects include Chromium and Chromium OS...</ex>$5</ph>
+        <ph name="TITLE"><ex>Learn about the new Chromium Projects</ex>$1</ph>, <ph name="PUBLISHER_INFORMATION"><ex>The Chromium organization</ex>$2</ph>, <ph name="PUBLICATION_DATE"><ex>January 1 2017</ex>$3</ph>, <ph name="STATE"><ex>Available offline</ex>$4</ph>
       </message>
       <message name="IDS_IOS_CONTENT_SUGGESTIONS_ACCESSIBILITY_AVAILABLE_OFFLINE" desc="Accessibility label to indicate that the suggestion is available offline. Read by Text-to-Speech.">
         Available offline
@@ -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/browser_state/chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
index b13131e..9379e7c8 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
@@ -95,6 +95,8 @@
     : state_path_(path),
       pref_registry_(new user_prefs::PrefRegistrySyncable),
       io_data_(new ChromeBrowserStateImplIOData::Handle(this)) {
+  BrowserState::Initialize(this, state_path_);
+
   otr_state_path_ = state_path_.Append(FILE_PATH_LITERAL("OTR"));
 
   bool directories_created =
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
index e9e9dc5..a5d5678d 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
@@ -21,6 +21,7 @@
       original_chrome_browser_state_(original_chrome_browser_state),
       prefs_(static_cast<sync_preferences::PrefServiceSyncable*>(
           original_chrome_browser_state->GetOffTheRecordPrefs())) {
+  BrowserState::Initialize(this, otr_state_path_);
   user_prefs::UserPrefs::Set(this, GetPrefs());
   io_data_.reset(new OffTheRecordChromeBrowserStateIOData::Handle(this));
   BrowserStateDependencyManager::GetInstance()->CreateBrowserStateServices(
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
index 095ec42b..3722da5d 100644
--- a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
@@ -176,6 +176,8 @@
   if (!base::PathExists(state_path_))
     base::CreateDirectory(state_path_);
 
+  BrowserState::Initialize(this, GetStatePath());
+
   // Normally this would happen during browser startup, but for tests we need to
   // trigger creation of BrowserState-related services.
   EnsureBrowserStateKeyedServiceFactoriesBuilt();
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.mm b/ios/chrome/browser/content_suggestions/mediator_util.mm
index 0c6115d..8826c3d8 100644
--- a/ios/chrome/browser/content_suggestions/mediator_util.mm
+++ b/ios/chrome/browser/content_suggestions/mediator_util.mm
@@ -47,7 +47,6 @@
   ContentSuggestionsItem* suggestion = [[ContentSuggestionsItem alloc]
       initWithType:0
              title:base::SysUTF16ToNSString(contentSuggestion.title())
-          subtitle:base::SysUTF16ToNSString(contentSuggestion.snippet_text())
                url:contentSuggestion.url()];
 
   suggestion.publisher =
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index b904c36..b1b56fe 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -48,6 +48,8 @@
     "EnableSlimNavigationManager", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableThirdPartyKeyboardWorkaround{
     "EnableThirdPartyKeyboardWorkaround", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIOSNTPSuggestions{"IOSNTPSuggestions",
+                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
 }  // namespace
 
@@ -239,8 +241,8 @@
   if (command_line->HasSwitch(switches::kDisableSuggestionsUI))
     return false;
 
-  // By default, disable it.
-  return false;
+  // Check if the Finch experiment is turned on.
+  return base::FeatureList::IsEnabled(kIOSNTPSuggestions);
 }
 
 bool IsSigninPromoEnabled() {
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/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index ba7c2658..43a28b99 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -639,9 +639,6 @@
 - (void)displayTab:(Tab*)tab isNewSelection:(BOOL)newSelection;
 // Initializes the bookmark interaction controller if not already initialized.
 - (void)initializeBookmarkInteractionController;
-
-// Shows the tools menu popup.
-- (void)showToolsMenuPopup;
 // Add all delegates to the provided |tab|.
 - (void)installDelegatesForTab:(Tab*)tab;
 // Remove delegates from the provided |tab|.
@@ -3438,56 +3435,6 @@
 
 #pragma mark - Showing popups
 
-- (void)showToolsMenuPopup {
-  DCHECK(_browserState);
-  DCHECK(self.visible || self.dismissingModal);
-
-  // Record the time this menu was requested; to be stored in the configuration
-  // object.
-  NSDate* showToolsMenuPopupRequestDate = [NSDate date];
-
-  // Dismiss the omnibox (if open).
-  [_toolbarController cancelOmniboxEdit];
-  // Dismiss the soft keyboard (if open).
-  [[_model currentTab].webController dismissKeyboard];
-  // Dismiss Find in Page focus.
-  [self updateFindBar:NO shouldFocus:NO];
-
-  ToolsMenuConfiguration* configuration =
-      [[ToolsMenuConfiguration alloc] initWithDisplayView:[self view]];
-  configuration.requestStartTime =
-      showToolsMenuPopupRequestDate.timeIntervalSinceReferenceDate;
-  if ([_model count] == 0)
-    [configuration setNoOpenedTabs:YES];
-
-  if (_isOffTheRecord)
-    [configuration setInIncognito:YES];
-
-  if (!_readingListMenuNotifier) {
-    _readingListMenuNotifier = [[ReadingListMenuNotifier alloc]
-        initWithReadingList:ReadingListModelFactory::GetForBrowserState(
-                                _browserState)];
-  }
-  [configuration setReadingListMenuNotifier:_readingListMenuNotifier];
-
-  [configuration setUserAgentType:self.userAgentType];
-
-  [_toolbarController showToolsMenuPopupWithConfiguration:configuration];
-
-  ToolsPopupController* toolsPopupController =
-      [_toolbarController toolsPopupController];
-  if ([_model currentTab]) {
-    BOOL isBookmarked = _toolbarModelIOS->IsCurrentTabBookmarked();
-    [toolsPopupController setIsCurrentPageBookmarked:isBookmarked];
-    [toolsPopupController setCanShowFindBar:self.canShowFindBar];
-    [toolsPopupController setCanUseReaderMode:self.canUseReaderMode];
-    [toolsPopupController setCanShowShareMenu:self.canShowShareMenu];
-
-    if (!IsIPadIdiom())
-      [toolsPopupController setIsTabLoading:_toolbarModelIOS->IsLoading()];
-  }
-}
-
 - (void)showPageInfoPopupForView:(UIView*)sourceView {
   Tab* tab = [_model currentTab];
   DCHECK([tab navigationManager]);
@@ -4059,6 +4006,56 @@
                  originRect:[_toolbarController bookmarkButtonAnchorRect]];
 }
 
+- (void)showToolsMenu {
+  DCHECK(_browserState);
+  DCHECK(self.visible || self.dismissingModal);
+
+  // Record the time this menu was requested; to be stored in the configuration
+  // object.
+  NSDate* showToolsMenuPopupRequestDate = [NSDate date];
+
+  // Dismiss the omnibox (if open).
+  [_toolbarController cancelOmniboxEdit];
+  // Dismiss the soft keyboard (if open).
+  [[_model currentTab].webController dismissKeyboard];
+  // Dismiss Find in Page focus.
+  [self updateFindBar:NO shouldFocus:NO];
+
+  ToolsMenuConfiguration* configuration =
+      [[ToolsMenuConfiguration alloc] initWithDisplayView:[self view]];
+  configuration.requestStartTime =
+      showToolsMenuPopupRequestDate.timeIntervalSinceReferenceDate;
+  if ([_model count] == 0)
+    [configuration setNoOpenedTabs:YES];
+
+  if (_isOffTheRecord)
+    [configuration setInIncognito:YES];
+
+  if (!_readingListMenuNotifier) {
+    _readingListMenuNotifier = [[ReadingListMenuNotifier alloc]
+        initWithReadingList:ReadingListModelFactory::GetForBrowserState(
+                                _browserState)];
+  }
+  [configuration setReadingListMenuNotifier:_readingListMenuNotifier];
+
+  [configuration setUserAgentType:self.userAgentType];
+
+  [_toolbarController showToolsMenuPopupWithConfiguration:configuration];
+
+  ToolsPopupController* toolsPopupController =
+      [_toolbarController toolsPopupController];
+  if ([_model currentTab]) {
+    BOOL isBookmarked = _toolbarModelIOS->IsCurrentTabBookmarked();
+    [toolsPopupController setIsCurrentPageBookmarked:isBookmarked];
+    [toolsPopupController setCanShowFindBar:self.canShowFindBar];
+    [toolsPopupController setCanUseReaderMode:self.canUseReaderMode];
+    [toolsPopupController setCanShowShareMenu:self.canShowShareMenu];
+
+    if (!IsIPadIdiom())
+      [toolsPopupController setIsTabLoading:_toolbarModelIOS->IsLoading()];
+  }
+}
+
 #pragma mark - Command Handling
 
 - (IBAction)chromeExecuteCommand:(id)sender {
@@ -4136,10 +4133,6 @@
     case IDC_REQUEST_MOBILE_SITE:
       [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::MOBILE];
       break;
-    case IDC_SHOW_TOOLS_MENU: {
-      [self showToolsMenuPopup];
-      break;
-    }
     case IDC_SHOW_BOOKMARK_MANAGER: {
       if (IsIPadIdiom()) {
         [self showAllBookmarks];
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h
index 54dcb2d..b7aa391 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h
@@ -18,6 +18,12 @@
 // The second line of detail text to display.
 @property(nonatomic, readonly, strong, nullable) UILabel* detailTextLabel;
 
+// Returns the height needed for a cell contained in |width| to display
+// |titleLabel| and |detailTextLabel|.
++ (CGFloat)heightForTitleLabel:(nullable UILabel*)titleLabel
+               detailTextLabel:(nullable UILabel*)detailTextLabel
+                         width:(CGFloat)width;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COLLECTION_VIEW_CELLS_COLLECTION_VIEW_TEXT_CELL_H_
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.mm
index d09758d..9a192999 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.mm
@@ -33,6 +33,8 @@
     _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [containerView addSubview:_detailTextLabel];
 
+    CGFloat margin = kMargin;
+
     [NSLayoutConstraint activateConstraints:@[
       // Total height.
       // The MDC specs ask for at least 48 pt.
@@ -42,16 +44,16 @@
       // Container.
       [containerView.leadingAnchor
           constraintEqualToAnchor:self.contentView.leadingAnchor
-                         constant:kMargin],
+                         constant:margin],
       [containerView.trailingAnchor
           constraintEqualToAnchor:self.contentView.trailingAnchor
-                         constant:-kMargin],
+                         constant:-margin],
       [containerView.topAnchor
           constraintGreaterThanOrEqualToAnchor:self.contentView.topAnchor
-                                      constant:kMargin],
+                                      constant:margin],
       [containerView.bottomAnchor
           constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
-                                   constant:-kMargin],
+                                   constant:-margin],
       [containerView.centerYAnchor
           constraintEqualToAnchor:self.contentView.centerYAnchor],
 
@@ -74,6 +76,18 @@
   return self;
 }
 
++ (CGFloat)heightForTitleLabel:(UILabel*)titleLabel
+               detailTextLabel:(UILabel*)detailTextLabel
+                         width:(CGFloat)width {
+  CGSize sizeForLabel = CGSizeMake(width - 2 * kMargin, 500);
+
+  CGFloat cellHeight = 2 * kMargin;
+  cellHeight += [titleLabel sizeThatFits:sizeForLabel].height;
+  cellHeight += [detailTextLabel sizeThatFits:sizeForLabel].height;
+
+  return MAX(cellHeight, kMinimalHeight);
+}
+
 // Implement -layoutSubviews as per instructions in documentation for
 // +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
 - (void)layoutSubviews {
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index 07ed08b..49df039e 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -30,6 +30,9 @@
 // Bookmarks the current page.
 - (void)bookmarkPage;
 
+// Shows the tools menu.
+- (void)showToolsMenu;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 0341252..6492497 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -24,7 +24,6 @@
 #define IDC_SHOW_BOOKMARK_MANAGER                      40011
 #define IDC_OPTIONS                                    40015
 #define IDC_HELP_PAGE_VIA_MENU                         40020
-#define IDC_SHOW_TOOLS_MENU                            40900
 #define IDC_TOGGLE_TAB_SWITCHER                        40901
 #define IDC_VOICE_SEARCH                               40902
 #define IDC_NEW_INCOGNITO_TAB                          40903
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h
index b8b15ce..82a15f05b 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h
@@ -27,9 +27,14 @@
                                              date:(NSString*)publishDate
                               offlineAvailability:(BOOL)availableOffline;
 
-// Setst the subtitle text. If |subtitle| is nil, the space taken by the
-// subtitle is removed.
-- (void)setSubtitleText:(NSString*)subtitle;
+// Returns the height needed by a cell contained in |width| and containing the
+// listed informations.
++ (CGFloat)heightForWidth:(CGFloat)width
+                withImage:(BOOL)hasImage
+                    title:(NSString*)title
+            publisherName:(NSString*)publisherName
+          publicationDate:(NSString*)publicationDate
+         availableOffline:(BOOL)availableOffline;
 
 @end
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
index 41c5626e..1863e0c 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -56,10 +56,6 @@
 @property(nonatomic, strong) NSLayoutConstraint* imageSize;
 // Constraint for the distance between the texts and the image.
 @property(nonatomic, strong) NSLayoutConstraint* imageTitleSpacing;
-// Constraint for the vertical distance between the title and the subtitle.
-@property(nonatomic, strong) NSLayoutConstraint* titleSubtitleSpacing;
-// Label for the subtitle.
-@property(nonatomic, readonly, strong) UILabel* subtitleLabel;
 
 // Applies the constraints on the elements. Called in the init.
 - (void)applyConstraints;
@@ -69,7 +65,6 @@
 @implementation ContentSuggestionsCell
 
 @synthesize titleLabel = _titleLabel;
-@synthesize subtitleLabel = _subtitleLabel;
 @synthesize imageContainer = _imageContainer;
 @synthesize noImageIcon = _noImageIcon;
 @synthesize additionalInformationLabel = _additionalInformationLabel;
@@ -78,26 +73,17 @@
 @synthesize imageSize = _imageSize;
 @synthesize imageTitleSpacing = _imageTitleSpacing;
 @synthesize displayImage = _displayImage;
-@synthesize titleSubtitleSpacing = _titleSubtitleSpacing;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
     _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     _imageContainer = [[UIView alloc] initWithFrame:CGRectZero];
     _noImageIcon = [[UIImageView alloc] initWithFrame:CGRectZero];
     _additionalInformationLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     _contentImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
     _faviconView = [[FaviconViewNew alloc] init];
 
-    _titleLabel.numberOfLines = 2;
-    _subtitleLabel.numberOfLines = 2;
-    [_subtitleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                                      forAxis:UILayoutConstraintAxisVertical];
-    [_titleLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh
-                                   forAxis:UILayoutConstraintAxisVertical];
-
     _contentImageView.contentMode = UIViewContentModeScaleAspectFill;
     _contentImageView.clipsToBounds = YES;
     _contentImageView.hidden = YES;
@@ -105,14 +91,12 @@
     _imageContainer.translatesAutoresizingMaskIntoConstraints = NO;
     _noImageIcon.translatesAutoresizingMaskIntoConstraints = NO;
     _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _additionalInformationLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _contentImageView.translatesAutoresizingMaskIntoConstraints = NO;
     _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
 
     [self.contentView addSubview:_imageContainer];
     [self.contentView addSubview:_titleLabel];
-    [self.contentView addSubview:_subtitleLabel];
     [self.contentView addSubview:_additionalInformationLabel];
     [self.contentView addSubview:_faviconView];
 
@@ -126,12 +110,10 @@
     [_noImageIcon
         setTintColor:[UIColor colorWithWhite:kNoImageIconWhite alpha:1]];
 
-    _titleLabel.font = [MDCTypography subheadFont];
-    _subtitleLabel.font = [MDCTypography body1Font];
-    _additionalInformationLabel.font = [MDCTypography captionFont];
+    [[self class] configureTitleLabel:_titleLabel];
+    _additionalInformationLabel.font = [[self class] additionalInformationFont];
     _faviconView.font = [[MDCTypography fontLoader] mediumFontOfSize:10];
 
-    _subtitleLabel.textColor = [[MDCPalette greyPalette] tint700];
     _additionalInformationLabel.textColor = [[MDCPalette greyPalette] tint700];
 
     [self applyConstraints];
@@ -163,36 +145,10 @@
 - (void)setAdditionalInformationWithPublisherName:(NSString*)publisherName
                                              date:(NSString*)date
                               offlineAvailability:(BOOL)availableOffline {
-  NSString* publisherString = AdjustStringForLocaleDirection(
-      [NSString stringWithFormat:@"%@ - %@ ", publisherName, date]);
-
-  NSMutableAttributedString* additionInformation =
-      [[NSMutableAttributedString alloc] initWithString:publisherString
-                                             attributes:nil];
-
-  if (availableOffline) {
-    NSTextAttachment* offlineIcon = [[NSTextAttachment alloc] init];
-    offlineIcon.image = [[UIImage imageNamed:kOfflineIconName]
-        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-    offlineIcon.bounds = CGRectMake(
-        0, (_additionalInformationLabel.font.xHeight - kOfflineIconSize) / 2,
-        kOfflineIconSize, kOfflineIconSize);
-
-    [additionInformation
-        appendAttributedString:[NSAttributedString
-                                   attributedStringWithAttachment:offlineIcon]];
-  }
-
-  self.additionalInformationLabel.attributedText = additionInformation;
-}
-
-- (void)setSubtitleText:(NSString*)subtitle {
-  self.subtitleLabel.text = subtitle;
-  if (subtitle.length > 0) {
-    self.titleSubtitleSpacing.constant = kSmallSpacing;
-  } else {
-    self.titleSubtitleSpacing.constant = 0;
-  }
+  self.additionalInformationLabel.attributedText =
+      [[self class] attributedStringForPublisher:publisherName
+                                            date:date
+                                availableOffline:availableOffline];
 }
 
 - (void)setDisplayImage:(BOOL)displayImage {
@@ -208,12 +164,40 @@
   _displayImage = displayImage;
 }
 
++ (CGFloat)heightForWidth:(CGFloat)width
+                withImage:(BOOL)hasImage
+                    title:(NSString*)title
+            publisherName:(NSString*)publisherName
+          publicationDate:(NSString*)publicationDate
+         availableOffline:(BOOL)availableOffline {
+  UILabel* titleLabel = [[UILabel alloc] init];
+  [self configureTitleLabel:titleLabel];
+  titleLabel.text = title;
+
+  UILabel* additionalInfoLabel = [[UILabel alloc] init];
+  additionalInfoLabel.font = [self additionalInformationFont];
+  additionalInfoLabel.attributedText =
+      [self attributedStringForPublisher:publisherName
+                                    date:publicationDate
+                        availableOffline:availableOffline];
+
+  CGSize sizeForLabels =
+      CGSizeMake(width - [self labelMarginWithImage:hasImage], 500);
+
+  CGFloat labelHeight = 3 * kStandardSpacing;
+  labelHeight += [titleLabel sizeThatFits:sizeForLabels].height;
+  labelHeight += [additionalInfoLabel sizeThatFits:sizeForLabels].height;
+
+  CGFloat minimalHeight = hasImage ? kImageSize : 0;
+  minimalHeight += 2 * kStandardSpacing;
+  return MAX(minimalHeight, labelHeight);
+}
+
 #pragma mark - UICollectionViewCell
 
 - (void)prepareForReuse {
   [super prepareForReuse];
   self.titleLabel.text = nil;
-  [self setSubtitleText:nil];
   self.displayImage = NO;
 }
 
@@ -228,15 +212,8 @@
   // changes, for instance on screen rotation.
   CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds);
 
-  CGFloat offset = 0;
-  if (self.displayImage) {
-    offset = kImageSize + kStandardSpacing;
-  }
-
   self.titleLabel.preferredMaxLayoutWidth =
-      parentWidth - 2 * kStandardSpacing - offset;
-  self.subtitleLabel.preferredMaxLayoutWidth =
-      parentWidth - 2 * kStandardSpacing - offset;
+      parentWidth - [[self class] labelMarginWithImage:self.displayImage];
   self.additionalInformationLabel.preferredMaxLayoutWidth =
       parentWidth - kFaviconSize - kSmallSpacing - 2 * kStandardSpacing;
 
@@ -253,9 +230,6 @@
   _imageTitleSpacing = [_imageContainer.leadingAnchor
       constraintEqualToAnchor:_titleLabel.trailingAnchor
                      constant:kStandardSpacing];
-  _titleSubtitleSpacing =
-      [_subtitleLabel.topAnchor constraintEqualToAnchor:_titleLabel.bottomAnchor
-                                               constant:kSmallSpacing];
 
   [NSLayoutConstraint activateConstraints:@[
     // Image.
@@ -263,29 +237,26 @@
     [_imageContainer.widthAnchor
         constraintEqualToAnchor:_imageContainer.heightAnchor],
     [_imageContainer.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor],
+    [_imageContainer.bottomAnchor
+        constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
+                                 constant:-kStandardSpacing],
 
     // Text.
-    _imageTitleSpacing, _titleSubtitleSpacing,
-    [_titleLabel.trailingAnchor
-        constraintEqualToAnchor:_subtitleLabel.trailingAnchor],
+    _imageTitleSpacing,
 
     // Additional Information.
     [_additionalInformationLabel.topAnchor
-        constraintGreaterThanOrEqualToAnchor:_imageContainer.bottomAnchor
-                                    constant:kStandardSpacing],
-    [_additionalInformationLabel.topAnchor
-        constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor
-                                    constant:kStandardSpacing],
+        constraintEqualToAnchor:_titleLabel.bottomAnchor
+                       constant:kStandardSpacing],
+    [_additionalInformationLabel.trailingAnchor
+        constraintEqualToAnchor:_titleLabel.trailingAnchor],
     [_additionalInformationLabel.bottomAnchor
         constraintLessThanOrEqualToAnchor:self.contentView.bottomAnchor
                                  constant:-kStandardSpacing],
 
     // Favicon.
     [_faviconView.topAnchor
-        constraintGreaterThanOrEqualToAnchor:_imageContainer.bottomAnchor
-                                    constant:kStandardSpacing],
-    [_faviconView.topAnchor
-        constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor
+        constraintGreaterThanOrEqualToAnchor:_titleLabel.bottomAnchor
                                     constant:kStandardSpacing],
     [_faviconView.centerYAnchor
         constraintEqualToAnchor:_additionalInformationLabel.centerYAnchor],
@@ -311,14 +282,12 @@
       @[
         @"H:|-(space)-[title]",
         @"H:[image]-(space)-|",
-        @"H:|-(space)-[text]",
         @"V:|-(space)-[title]",
-        @"H:|-(space)-[favicon]-(small)-[additional]-(space)-|",
+        @"H:|-(space)-[favicon]-(small)-[additional]",
       ],
       @{
         @"image" : _imageContainer,
         @"title" : _titleLabel,
-        @"text" : _subtitleLabel,
         @"additional" : _additionalInformationLabel,
         @"favicon" : _faviconView,
       },
@@ -326,4 +295,47 @@
          @"small" : @(kSmallSpacing) });
 }
 
+// Configures the |titleLabel|.
++ (void)configureTitleLabel:(UILabel*)titleLabel {
+  titleLabel.font = [MDCTypography subheadFont];
+  titleLabel.numberOfLines = 2;
+}
+
+// Returns the font used to display the additional informations.
++ (UIFont*)additionalInformationFont {
+  return [MDCTypography captionFont];
+}
+
+// Returns the margin for the labels, depending if the cell |hasImage|.
++ (CGFloat)labelMarginWithImage:(BOOL)hasImage {
+  CGFloat offset = hasImage ? kImageSize + kStandardSpacing : 0;
+  return 2 * kStandardSpacing + offset;
+}
+
+// Returns the attributed string to be displayed.
++ (NSAttributedString*)attributedStringForPublisher:(NSString*)publisherName
+                                               date:(NSString*)date
+                                   availableOffline:(BOOL)availableOffline {
+  NSString* publisherString = AdjustStringForLocaleDirection(
+      [NSString stringWithFormat:@"%@ - %@ ", publisherName, date]);
+
+  NSMutableAttributedString* additionInformation =
+      [[NSMutableAttributedString alloc] initWithString:publisherString
+                                             attributes:nil];
+
+  if (availableOffline) {
+    NSTextAttachment* offlineIcon = [[NSTextAttachment alloc] init];
+    offlineIcon.image = [[UIImage imageNamed:kOfflineIconName]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    offlineIcon.bounds = CGRectMake(
+        0, ([self additionalInformationFont].xHeight - kOfflineIconSize) / 2,
+        kOfflineIconSize, kOfflineIconSize);
+
+    [additionInformation
+        appendAttributedString:[NSAttributedString
+                                   attributedStringWithAttachment:offlineIcon]];
+  }
+  return additionInformation;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
index d0f0339..1d96f018 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h
@@ -22,7 +22,6 @@
 // to the full article. |type| is the type of the item.
 - (instancetype)initWithType:(NSInteger)type
                        title:(NSString*)title
-                    subtitle:(NSString*)subtitle
                          url:(const GURL&)url NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithType:(NSInteger)type NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
index 81e79a7..d297b327 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
@@ -21,7 +21,6 @@
 
 @interface ContentSuggestionsItem ()
 
-@property(nonatomic, copy) NSString* subtitle;
 // Used to check if the image has already been fetched. There is no way to
 // discriminate between failed image download and nonexitent image. The
 // suggestion tries to download the image only once.
@@ -36,7 +35,6 @@
 @implementation ContentSuggestionsItem
 
 @synthesize title = _title;
-@synthesize subtitle = _subtitle;
 @synthesize image = _image;
 @synthesize URL = _URL;
 @synthesize publisher = _publisher;
@@ -52,13 +50,11 @@
 
 - (instancetype)initWithType:(NSInteger)type
                        title:(NSString*)title
-                    subtitle:(NSString*)subtitle
                          url:(const GURL&)url {
   self = [super initWithType:type];
   if (self) {
     self.cellClass = [ContentSuggestionsCell class];
     _title = [title copy];
-    _subtitle = [subtitle copy];
     _URL = url;
   }
   return self;
@@ -73,7 +69,6 @@
   }
   [cell.faviconView configureWithAttributes:self.attributes];
   cell.titleLabel.text = self.title;
-  [cell setSubtitleText:self.subtitle];
   cell.displayImage = self.hasImage;
   [cell setContentImage:self.image animated:self.firstTimeWithImage];
   self.firstTimeWithImage = NO;
@@ -90,6 +85,15 @@
     self.firstTimeWithImage = YES;
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  return [self.cellClass heightForWidth:width
+                              withImage:self.hasImage
+                                  title:self.title
+                          publisherName:self.publisher
+                        publicationDate:[self relativeDate]
+                       availableOffline:self.availableOffline];
+}
+
 #pragma mark - Private
 
 // Returns the date of publication relative to now.
@@ -124,8 +128,7 @@
       base::SysNSStringToUTF16(self.title),
       base::SysNSStringToUTF16(self.publisher),
       base::SysNSStringToUTF16([self relativeDate]),
-      base::SysNSStringToUTF16(offlineAvailability),
-      base::SysNSStringToUTF16(self.subtitle));
+      base::SysNSStringToUTF16(offlineAvailability));
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
index 71ad70b..713552c9 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item_unittest.mm
@@ -24,7 +24,6 @@
 TEST(ContentSuggestionsItemTest, CellIsConfiguredWithoutImage) {
   // Setup.
   NSString* title = @"testTitle";
-  NSString* subtitle = @"testSubtitle";
   GURL url = GURL("http://chromium.org");
   NSString* publisher = @"publisherName";
   base::Time publishTime = base::Time::Now();
@@ -33,7 +32,6 @@
   ContentSuggestionsItem* item =
       [[ContentSuggestionsItem alloc] initWithType:0
                                              title:title
-                                          subtitle:subtitle
                                                url:url];
   item.delegate = delegateMock;
   item.hasImage = YES;
@@ -47,7 +45,6 @@
   ASSERT_EQ(nil, item.image);
   id cellMock = OCMPartialMock(cell);
   OCMExpect([cellMock setContentImage:item.image animated:NO]);
-  OCMExpect([cellMock setSubtitleText:subtitle]);
   OCMExpect([cellMock setAdditionalInformationWithPublisherName:publisher
                                                            date:date
                                             offlineAvailability:YES]);
@@ -66,13 +63,11 @@
 TEST(ContentSuggestionsItemTest, DontFetchImageIsImageIsBeingFetched) {
   // Setup.
   NSString* title = @"testTitle";
-  NSString* subtitle = @"testSubtitle";
   GURL url = GURL("http://chromium.org");
   id niceDelegateMock = OCMProtocolMock(@protocol(SuggestedContentDelegate));
   ContentSuggestionsItem* item =
       [[ContentSuggestionsItem alloc] initWithType:0
                                              title:title
-                                          subtitle:subtitle
                                                url:url];
   item.delegate = niceDelegateMock;
   item.hasImage = YES;
@@ -103,14 +98,12 @@
 TEST(ContentSuggestionsItemTest, NoDelegateCallWhenHasNotImage) {
   // Setup.
   NSString* title = @"testTitle";
-  NSString* subtitle = @"testSubtitle";
   GURL url = GURL("http://chromium.org");
   // Strict mock. Raise exception if the load method is called.
   id delegateMock = OCMStrictProtocolMock(@protocol(SuggestedContentDelegate));
   ContentSuggestionsItem* item =
       [[ContentSuggestionsItem alloc] initWithType:0
                                              title:title
-                                          subtitle:subtitle
                                                url:url];
   item.delegate = delegateMock;
   item.hasImage = NO;
@@ -124,12 +117,10 @@
 TEST(ContentSuggestionsItemTest, ImageAnimatedOnlyTheFirstTime) {
   // Setup.
   NSString* title = @"testTitle";
-  NSString* subtitle = @"testSubtitle";
   GURL url = GURL("http://chromium.org");
   ContentSuggestionsItem* item =
       [[ContentSuggestionsItem alloc] initWithType:0
                                              title:title
-                                          subtitle:subtitle
                                                url:url];
   item.hasImage = YES;
   item.image = [[UIImage alloc] init];
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
index c1006c6c..3fb2483a 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.mm
@@ -50,4 +50,8 @@
              : ntp_tiles::TileVisualType::ICON_COLOR;
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  return [ContentSuggestionsMostVisitedCell defaultSize].height;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm
index 26e76851a..b1d4b9d 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_text_item.mm
@@ -32,14 +32,8 @@
 - (void)configureCell:(CollectionViewTextCell*)cell {
   [super configureCell:cell];
 
-  cell.textLabel.text = self.text;
-  cell.textLabel.textColor = [[MDCPalette greyPalette] tint900];
-  cell.textLabel.font = [MDCTypography body2Font];
-  cell.textLabel.numberOfLines = 0;
-  cell.detailTextLabel.text = self.detailText;
-  cell.detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
-  cell.detailTextLabel.font = [MDCTypography body1Font];
-  cell.detailTextLabel.numberOfLines = 0;
+  [self configureTextLabel:cell.textLabel];
+  [self configureDetailTextLabel:cell.detailTextLabel];
 
   cell.isAccessibilityElement = YES;
   if (self.detailText.length == 0) {
@@ -50,4 +44,33 @@
   }
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  UILabel* textLabel = [[UILabel alloc] init];
+  UILabel* detailTextLabel = [[UILabel alloc] init];
+  [self configureTextLabel:textLabel];
+  [self configureDetailTextLabel:detailTextLabel];
+
+  return [self.cellClass heightForTitleLabel:textLabel
+                             detailTextLabel:detailTextLabel
+                                       width:width];
+}
+
+#pragma mark - Private
+
+// Configures the |textLabel|.
+- (void)configureTextLabel:(UILabel*)textLabel {
+  textLabel.text = self.text;
+  textLabel.textColor = [[MDCPalette greyPalette] tint900];
+  textLabel.font = [MDCTypography body2Font];
+  textLabel.numberOfLines = 0;
+}
+
+// Configures the |detailTextLabel|.
+- (void)configureDetailTextLabel:(UILabel*)detailTextLabel {
+  detailTextLabel.text = self.detailText;
+  detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
+  detailTextLabel.font = [MDCTypography body1Font];
+  detailTextLabel.numberOfLines = 0;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h
index 50f19b16..4ab39d58 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h
@@ -24,6 +24,8 @@
 - (void)setIcon:(nullable UIImage*)icon;
 // Sets the text displayed.
 - (void)setText:(nullable NSString*)text;
+// Returns the height needed by a cell contained in |width| containing |text|.
++ (CGFloat)heightForWidth:(CGFloat)width withText:(nullable NSString*)text;
 
 @end
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
index 1c731540..5c35753 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
@@ -50,6 +50,10 @@
   [cell setText:self.text];
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  return [self.cellClass heightForWidth:width withText:self.text];
+}
+
 @end
 
 #pragma mark - ContentSuggestionsWhatsNewCell
@@ -73,10 +77,6 @@
   if (self) {
     _iconView = [[UIImageView alloc] init];
     _promoLabel = [[UILabel alloc] init];
-    _promoLabel.font =
-        [[MDCTypography fontLoader] regularFontOfSize:kLabelFontSize];
-    _promoLabel.textColor = UIColorFromRGB(kTextColorRGB, 1.0);
-    _promoLabel.numberOfLines = 0;
     _containerView = [[UIView alloc] init];
 
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
@@ -117,6 +117,45 @@
 }
 
 - (void)setText:(NSString*)text {
+  [[self class] configureLabel:self.promoLabel withText:text];
+}
+
++ (CGFloat)heightForWidth:(CGFloat)width withText:(NSString*)text {
+  UILabel* label = [[UILabel alloc] init];
+  [self configureLabel:label withText:text];
+  CGSize sizeForLabel = CGSizeMake(width - kLabelIconMargin - kIconSize, 500);
+
+  return 2 * kLabelMargin + [label sizeThatFits:sizeForLabel].height;
+}
+
+#pragma mark UIView
+
+// Implements -layoutSubviews as per instructions in documentation for
+// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
+- (void)layoutSubviews {
+  [super layoutSubviews];
+
+  // Adjust the text label preferredMaxLayoutWidth when the parent's width
+  // changes, for instance on screen rotation.
+  CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds);
+
+  self.promoLabel.preferredMaxLayoutWidth =
+      parentWidth - kIconSize - kLabelIconMargin;
+
+  // Re-layout with the new preferred width to allow the label to adjust its
+  // height.
+  [super layoutSubviews];
+}
+
+#pragma mark Private
+
+// Configures the |promoLabel| with the |text|.
++ (void)configureLabel:(UILabel*)promoLabel withText:(NSString*)text {
+  promoLabel.font =
+      [[MDCTypography fontLoader] regularFontOfSize:kLabelFontSize];
+  promoLabel.textColor = UIColorFromRGB(kTextColorRGB, 1.0);
+  promoLabel.numberOfLines = 0;
+
   NSRange linkRange;
   NSString* strippedText = ParseStringWithLink(text, &linkRange);
   DCHECK_NE(NSNotFound, static_cast<NSInteger>(linkRange.location));
@@ -145,26 +184,7 @@
                          value:style
                          range:NSMakeRange(0, strLength)];
 
-  [self.promoLabel setAttributedText:attributedText];
-}
-
-#pragma mark UIView
-
-// Implements -layoutSubviews as per instructions in documentation for
-// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  // Adjust the text label preferredMaxLayoutWidth when the parent's width
-  // changes, for instance on screen rotation.
-  CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds);
-
-  self.promoLabel.preferredMaxLayoutWidth =
-      parentWidth - kIconSize - kLabelIconMargin;
-
-  // Re-layout with the new preferred width to allow the label to adjust its
-  // height.
-  [super layoutSubviews];
+  [promoLabel setAttributedText:attributedText];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h b/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h
index bc5dfec..2e6b87b 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h
@@ -29,6 +29,9 @@
 // Identifier for this content.
 @property(nonatomic, strong) ContentSuggestionIdentifier* suggestionIdentifier;
 
+// The height needed by a cell configured by this item, for a |width|.
+- (CGFloat)cellHeightForWidth:(CGFloat)width;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_SUGGESTED_CONTENT_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index 1f6b8a3..293db52 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -25,6 +25,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h"
 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h"
 #import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h"
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -526,6 +527,7 @@
     CollectionViewTextItem* header =
         [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
     header.text = sectionInfo.title;
+    header.textColor = [[MDCPalette greyPalette] tint500];
     [self.collectionViewController.collectionViewModel
                        setHeader:header
         forSectionWithIdentifier:sectionIdentifier];
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 95ba674..7c53b521 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h"
+#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_commands.h"
@@ -360,18 +361,16 @@
 
 - (CGFloat)collectionView:(UICollectionView*)collectionView
     cellHeightAtIndexPath:(NSIndexPath*)indexPath {
-  CollectionViewItem* item =
+  CSCollectionViewItem* item =
       [self.collectionViewModel itemAtIndexPath:indexPath];
   UIEdgeInsets inset = [self collectionView:collectionView
                                      layout:collectionView.collectionViewLayout
                      insetForSectionAtIndex:indexPath.section];
   UIEdgeInsets contentInset = self.collectionView.contentInset;
+  CGFloat width = CGRectGetWidth(collectionView.bounds) - inset.left -
+                  inset.right - contentInset.left - contentInset.right;
 
-  return [MDCCollectionViewCell
-      cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds) -
-                                 inset.left - inset.right - contentInset.left -
-                                 contentInset.right
-                         forItem:item];
+  return [item cellHeightForWidth:width];
 }
 
 #pragma mark - MDCCollectionViewEditingDelegate
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/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index 4b6c87c..20c9246c 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -715,9 +715,6 @@
   ContentSuggestionsItem* articleItem = [[ContentSuggestionsItem alloc]
       initWithType:ItemTypeContentSuggestions
              title:@"This is an incredible article, you should read it!"
-          subtitle:@"Really, this is the best article I have ever seen, it "
-                   @"is mandatory to read it! It describes how to write "
-                   @"the best article."
                url:GURL()];
   articleItem.publisher = @"Top Publisher.com";
   return articleItem;
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_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
index 2acbaba4..318c8c49 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -292,6 +292,14 @@
 
 - (void)dealloc {
   [self stopBrowserStateServiceObservers];
+  if (!_signinStarted && _signinPromoViewMediator) {
+    PrefService* prefs = _browserState->GetPrefs();
+    int displayedCount =
+        prefs->GetInteger(prefs::kIosSettingsSigninPromoDisplayedCount);
+    UMA_HISTOGRAM_COUNTS_100(
+        "MobileSignInPromo.SettingsManager.ImpressionsTilDismiss",
+        displayedCount);
+  }
 }
 
 - (void)stopBrowserStateServiceObservers {
@@ -315,18 +323,6 @@
   [self updateSearchCell];
 }
 
-- (void)viewDidDisappear:(BOOL)animated {
-  [super viewDidDisappear:animated];
-  if (!_signinStarted && _signinPromoViewMediator) {
-    PrefService* prefs = _browserState->GetPrefs();
-    int displayedCount =
-        prefs->GetInteger(prefs::kIosSettingsSigninPromoDisplayedCount);
-    UMA_HISTOGRAM_COUNTS_100(
-        "MobileSignInPromo.SettingsManager.ImpressionsTilDismiss",
-        displayedCount);
-  }
-}
-
 #pragma mark SettingsRootCollectionViewController
 
 - (void)loadModel {
@@ -351,11 +347,13 @@
         prefs->GetInteger(prefs::kIosSettingsSigninPromoDisplayedCount);
     if (experimental_flags::IsSigninPromoEnabled() &&
         displayedCount < kAutomaticSigninPromoViewDismissCount) {
-      _signinPromoViewMediator =
-          [[SigninPromoViewMediator alloc] initWithBrowserState:_browserState];
-      _signinPromoViewMediator.consumer = self;
-      prefs->SetInteger(prefs::kIosSettingsSigninPromoDisplayedCount,
-                        displayedCount + 1);
+      if (!_signinPromoViewMediator) {
+        _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
+            initWithBrowserState:_browserState];
+        _signinPromoViewMediator.consumer = self;
+        prefs->SetInteger(prefs::kIosSettingsSigninPromoDisplayedCount,
+                          displayedCount + 1);
+      }
     }
     [model addItem:[self signInTextItem]
         toSectionWithIdentifier:SectionIdentifierSignIn];
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/stack_view/BUILD.gn b/ios/chrome/browser/ui/stack_view/BUILD.gn
index 2e21fc2..5ed9bea 100644
--- a/ios/chrome/browser/ui/stack_view/BUILD.gn
+++ b/ios/chrome/browser/ui/stack_view/BUILD.gn
@@ -56,6 +56,7 @@
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/browser/ui/tools_menu",
     "//ios/chrome/common",
+    "//ios/shared/chrome/browser/ui/commands",
     "//ios/shared/chrome/browser/ui/tools_menu",
     "//ios/third_party/material_components_ios",
     "//ios/web",
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
index 91ed3a1..842faec 100644
--- a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
+++ b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
@@ -29,6 +29,7 @@
 #import "ios/chrome/browser/ui/animation_util.h"
 #import "ios/chrome/browser/ui/background_generator.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
@@ -51,6 +52,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/material_timing.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/shared/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
 #include "ios/web/public/referrer.h"
 #import "net/base/mac/url_conversions.h"
@@ -490,6 +492,8 @@
   // |YES| if there is card set animation being processed. For testing only.
   // Save last touch point used by new tab animation.
   CGPoint _lastTapPoint;
+  // The dispacther instance used when this view controller is active.
+  CommandDispatcher* _dispatcher;
 }
 
 @synthesize activeCardSet = _activeCardSet;
@@ -530,6 +534,9 @@
         initWithTarget:self
                 action:@selector(handleTapFrom:)];
     [_modeSwitchRecognizer setDelegate:self];
+    _dispatcher = [[CommandDispatcher alloc] init];
+    [_dispatcher startDispatchingToTarget:self
+                              forProtocol:@protocol(BrowserCommands)];
   }
   return self;
 }
@@ -560,6 +567,10 @@
   return nil;
 }
 
+- (id<BrowserCommands>)dispatcher {
+  return static_cast<id<BrowserCommands>>(_dispatcher);
+}
+
 - (void)setUpWithMainCardSet:(CardSet*)mainCardSet
                   otrCardSet:(CardSet*)otrCardSet
                activeCardSet:(CardSet*)activeCardSet {
@@ -2683,13 +2694,26 @@
   return nil;
 }
 
+#pragma mark - BrowserCommands
+
+- (void)showToolsMenu {
+  ToolsMenuConfiguration* configuration =
+      [[ToolsMenuConfiguration alloc] initWithDisplayView:[self view]];
+  [configuration setInTabSwitcher:YES];
+  // When checking for the existence of tabs, catch the case where the main set
+  // is both active and empty, but the incognito set has some cards.
+  if (([[_activeCardSet cards] count] == 0) &&
+      (_activeCardSet == _otrCardSet || [[_otrCardSet cards] count] == 0))
+    [configuration setNoOpenedTabs:YES];
+  if (_activeCardSet == _otrCardSet)
+    [configuration setInIncognito:YES];
+  [_toolbarController showToolsMenuPopupWithConfiguration:configuration];
+}
+
 - (IBAction)chromeExecuteCommand:(id)sender {
   int command = [sender tag];
 
   switch (command) {
-    case IDC_SHOW_TOOLS_MENU:
-      [self showToolsMenuPopup];
-      break;
     // Closing all while the main set is active closes everything, but closing
     // all while incognito is active only closes incognito tabs.
     case IDC_CLOSE_ALL_TABS:
@@ -2720,20 +2744,6 @@
   }
 }
 
-- (void)showToolsMenuPopup {
-  ToolsMenuConfiguration* configuration =
-      [[ToolsMenuConfiguration alloc] initWithDisplayView:[self view]];
-  [configuration setInTabSwitcher:YES];
-  // When checking for the existence of tabs, catch the case where the main set
-  // is both active and empty, but the incognito set has some cards.
-  if (([[_activeCardSet cards] count] == 0) &&
-      (_activeCardSet == _otrCardSet || [[_otrCardSet cards] count] == 0))
-    [configuration setNoOpenedTabs:YES];
-  if (_activeCardSet == _otrCardSet)
-    [configuration setInIncognito:YES];
-  [_toolbarController showToolsMenuPopupWithConfiguration:configuration];
-}
-
 #pragma mark Notification Handlers
 
 - (void)allModelTabsHaveClosed:(NSNotification*)notify {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher.h
index 5f3934d3..954e537 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher.h
@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
 #include "ios/chrome/browser/ui/tab_switcher/tab_switcher_transition_context.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
@@ -50,6 +50,9 @@
 // switcher.
 @property(nonatomic, assign) id<TabSwitcherDelegate> delegate;
 
+// The dispatcher for browser-ish commands.
+@property(nonatomic, readonly) id<BrowserCommands> dispatcher;
+
 // Restores the internal state of the tab switcher with the given tab models,
 // which must not be nil. |activeTabModel| is the model which starts active,
 // and must be one of the other two models. Should only be called when the
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
index 9e2ac2e1..fbf31011 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
@@ -374,6 +374,12 @@
   return _delegate;
 }
 
+- (id<BrowserCommands>)dispatcher {
+  // TODO(crbug.com/738881) add a dispatcher instance to this class and
+  // return it here when needed.
+  return nil;
+}
+
 - (IBAction)chromeExecuteCommand:(id)sender {
   int command = [sender tag];
 
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index 3921ae95..fc8b8f67 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -288,7 +288,9 @@
     toolsMenuButton_ =
         [[ToolbarToolsMenuButton alloc] initWithFrame:toolsMenuButtonFrame
                                                 style:style_];
-    [toolsMenuButton_ setTag:IDC_SHOW_TOOLS_MENU];
+    [toolsMenuButton_ addTarget:self.dispatcher
+                         action:@selector(showToolsMenu)
+               forControlEvents:UIControlEventTouchUpInside];
     [toolsMenuButton_
         setAutoresizingMask:UIViewAutoresizingFlexibleLeadingMargin() |
                             UIViewAutoresizingFlexibleBottomMargin];
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
index 7fada93..b261679 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
@@ -46,6 +46,7 @@
   TOOLS_BOOKMARK_ITEM = -3,
   TOOLS_BOOKMARK_EDIT = -4,
   TOOLS_SHARE_ITEM = -5,
+  TOOLS_MENU_ITEM = -6,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLS_MENU_TOOLS_MENU_CONSTANTS_H_
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..4899098d 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];
@@ -485,10 +488,9 @@
 - (void)buttonPressed:(id)sender {
   int commandId = [sender tag];
   DCHECK(commandId);
-  // Do nothing when tapping the tools menu a second time.
   // Do not use -chromeExecuteCommand: for tags < 0 -- that is, items that have
   // been refactored to use the dispatcher.
-  if (commandId != IDC_SHOW_TOOLS_MENU && commandId > 0) {
+  if (commandId > 0) {
     [self chromeExecuteCommand:sender];
   }
 
@@ -595,6 +597,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/browser/ui/tools_menu/tools_menu_view_tools_cell.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm
index 9935171a..fddd391 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_tools_cell.mm
@@ -78,7 +78,7 @@
   int tools[2][3] = TOOLBAR_IDR_ONE_STATE(TOOLS_PRESSED);
   _toolsButton =
       [self newButtonForImageIds:tools
-                       commandID:IDC_SHOW_TOOLS_MENU
+                       commandID:TOOLS_MENU_ITEM
             accessibilityLabelID:IDS_IOS_TOOLBAR_CLOSE_MENU
                   automationName:@"kToolbarToolsMenuButtonIdentifier"];
 
diff --git a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
index b5b339f..cfb14a9 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
@@ -227,7 +227,7 @@
     case IDC_VIEW_SOURCE:
       // Debug only; no metric.
       break;
-    case IDC_SHOW_TOOLS_MENU:
+    case TOOLS_MENU_ITEM:
       // Do nothing when tapping the tools menu a second time.
       break;
     case IDC_SHOW_READING_LIST:
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/showcase/content_suggestions/sc_content_suggestions_data_source.mm b/ios/showcase/content_suggestions/sc_content_suggestions_data_source.mm
index bcd9e3cb..67cd4e77 100644
--- a/ios/showcase/content_suggestions/sc_content_suggestions_data_source.mm
+++ b/ios/showcase/content_suggestions/sc_content_suggestions_data_source.mm
@@ -88,7 +88,6 @@
     case ContentSuggestionsSectionReadingList: {
       SCContentSuggestionsItem* suggestion = [self article];
       suggestion.title = [[self class] titleReadingListItem];
-      suggestion.subtitle = nil;
       suggestion.hasImage = NO;
       suggestion.suggestionIdentifier.sectionInfo = self.readingListSection;
       return @[ suggestion ];
@@ -231,7 +230,6 @@
   SCContentSuggestionsItem* suggestion =
       [[SCContentSuggestionsItem alloc] initWithType:0];
   suggestion.title = @"Title";
-  suggestion.subtitle = @"Subtitle for this greeeeeaaaaaat suggestion!";
   suggestion.publisher = @"Publisher of the new";
   suggestion.hasImage = YES;
   suggestion.publicationDate = [self randomDate];
diff --git a/ios/showcase/content_suggestions/sc_content_suggestions_item.h b/ios/showcase/content_suggestions/sc_content_suggestions_item.h
index 4425be0c..fd3235d7 100644
--- a/ios/showcase/content_suggestions/sc_content_suggestions_item.h
+++ b/ios/showcase/content_suggestions/sc_content_suggestions_item.h
@@ -16,7 +16,6 @@
 @interface SCContentSuggestionsItem : CollectionViewItem<SuggestedContent>
 
 @property(nonatomic, copy) NSString* title;
-@property(nonatomic, copy) NSString* subtitle;
 @property(nonatomic, assign) BOOL hasImage;
 @property(nonatomic, copy) NSString* publisher;
 @property(nonatomic, copy) NSString* publicationDate;
diff --git a/ios/showcase/content_suggestions/sc_content_suggestions_item.mm b/ios/showcase/content_suggestions/sc_content_suggestions_item.mm
index 2b04182c..982fac8 100644
--- a/ios/showcase/content_suggestions/sc_content_suggestions_item.mm
+++ b/ios/showcase/content_suggestions/sc_content_suggestions_item.mm
@@ -18,7 +18,6 @@
 @synthesize suggestionIdentifier;
 @synthesize image;
 @synthesize title;
-@synthesize subtitle;
 @synthesize hasImage;
 @synthesize publisher;
 @synthesize publicationDate;
@@ -36,7 +35,6 @@
   [super configureCell:cell];
   [cell.faviconView configureWithAttributes:self.attributes];
   cell.titleLabel.text = self.title;
-  [cell setSubtitleText:self.subtitle];
   cell.displayImage = self.hasImage;
   [cell setContentImage:self.image animated:NO];
   [cell setAdditionalInformationWithPublisherName:self.publisher
@@ -51,4 +49,13 @@
   return self.title;
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  return [self.cellClass heightForWidth:width
+                              withImage:self.hasImage
+                                  title:self.title
+                          publisherName:self.publisher
+                        publicationDate:self.publicationDate
+                       availableOffline:self.availableOffline];
+}
+
 @end
diff --git a/ios/showcase/content_suggestions/sc_content_suggestions_most_visited_item.mm b/ios/showcase/content_suggestions/sc_content_suggestions_most_visited_item.mm
index 0dc3a319d..bb0f131 100644
--- a/ios/showcase/content_suggestions/sc_content_suggestions_most_visited_item.mm
+++ b/ios/showcase/content_suggestions/sc_content_suggestions_most_visited_item.mm
@@ -34,4 +34,8 @@
   [cell.faviconView configureWithAttributes:self.attributes];
 }
 
+- (CGFloat)cellHeightForWidth:(CGFloat)width {
+  return [ContentSuggestionsMostVisitedCell defaultSize].height;
+}
+
 @end
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 99f88ee3..01c9fa40 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -4,13 +4,21 @@
 
 #include "ios/web/public/browser_state.h"
 
+#include "base/guid.h"
+#include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
+#include "base/process/process_handle.h"
 #include "ios/web/active_state_manager_impl.h"
 #include "ios/web/public/certificate_policy_cache.h"
+#include "ios/web/public/service_manager_connection.h"
+#include "ios/web/public/service_names.mojom.h"
+#include "ios/web/public/web_client.h"
 #include "ios/web/public/web_thread.h"
 #include "ios/web/webui/url_data_manager_ios_backend.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/interfaces/service.mojom.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -18,6 +26,11 @@
 
 namespace web {
 namespace {
+
+// Maps service userIds to associated BrowserState instances.
+base::LazyInstance<std::map<std::string, BrowserState*>>::DestructorAtExit
+    g_user_id_to_browser_state = LAZY_INSTANCE_INITIALIZER;
+
 // Private key used for safe conversion of base::SupportsUserData to
 // web::BrowserState in web::BrowserState::FromSupportsUserData.
 const char kBrowserStateIdentifierKey[] = "BrowserStateIdentifierKey";
@@ -25,6 +38,9 @@
 // Data key names.
 const char kCertificatePolicyCacheKeyName[] = "cert_policy_cache";
 const char kActiveStateManagerKeyName[] = "active_state_manager";
+const char kMojoWasInitialized[] = "mojo-was-initialized";
+const char kServiceManagerConnection[] = "service-manager-connection";
+const char kServiceUserId[] = "service-user-id";
 
 // Wraps a CertificatePolicyCache as a SupportsUserData::Data; this is necessary
 // since reference counted objects can't be user data.
@@ -34,8 +50,58 @@
 
   scoped_refptr<CertificatePolicyCache> policy_cache;
 };
+
+// Container for a service userId to support association between BrowserStates
+// and service UserIds.
+class ServiceUserIdHolder : public base::SupportsUserData::Data {
+ public:
+  explicit ServiceUserIdHolder(const std::string& user_id)
+      : user_id_(user_id) {}
+  ~ServiceUserIdHolder() override {}
+
+  const std::string& user_id() const { return user_id_; }
+
+ private:
+  std::string user_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceUserIdHolder);
+};
+
+// Eliminates the mapping from |browser_state|'s associated userId (if any) to
+// |browser_state|.
+void RemoveBrowserStateFromUserIdMap(BrowserState* browser_state) {
+  ServiceUserIdHolder* holder = static_cast<ServiceUserIdHolder*>(
+      browser_state->GetUserData(kServiceUserId));
+  if (holder) {
+    g_user_id_to_browser_state.Get().erase(holder->user_id());
+  }
 }
 
+// Container for a ServiceManagerConnection to support association between
+// a BrowserState and the ServiceManagerConnection initiated on behalf of that
+// BrowserState.
+class BrowserStateServiceManagerConnectionHolder
+    : public base::SupportsUserData::Data {
+ public:
+  explicit BrowserStateServiceManagerConnectionHolder(
+      service_manager::mojom::ServiceRequest request)
+      : service_manager_connection_(ServiceManagerConnection::Create(
+            std::move(request),
+            WebThread::GetTaskRunnerForThread(WebThread::IO))) {}
+  ~BrowserStateServiceManagerConnectionHolder() override {}
+
+  ServiceManagerConnection* service_manager_connection() {
+    return service_manager_connection_.get();
+  }
+
+ private:
+  std::unique_ptr<ServiceManagerConnection> service_manager_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserStateServiceManagerConnectionHolder);
+};
+
+}  // namespace
+
 // static
 scoped_refptr<CertificatePolicyCache> BrowserState::GetCertificatePolicyCache(
     BrowserState* browser_state) {
@@ -85,6 +151,12 @@
 }
 
 BrowserState::~BrowserState() {
+  CHECK(GetUserData(kMojoWasInitialized))
+      << "Attempting to destroy a BrowserState that never called "
+      << "Initialize()";
+
+  RemoveBrowserStateFromUserIdMap(this);
+
   // Delete the URLDataManagerIOSBackend instance on the IO thread if it has
   // been created. Note that while this check can theoretically race with a
   // call to |GetURLDataManagerIOSBackendOnIOThread()|, if any clients of this
@@ -115,4 +187,93 @@
   }
   return static_cast<BrowserState*>(supports_user_data);
 }
+
+// static
+void BrowserState::Initialize(BrowserState* browser_state,
+                              const base::FilePath& path) {
+  std::string new_id = base::GenerateGUID();
+
+  // Note: If the file service is ever used on iOS, code needs to be added here
+  // to have the file service associate |path| as the user dir of the user Id
+  // of |browser_state| (see corresponding code in
+  // content::BrowserContext::Initialize). crbug.com/739450
+
+  RemoveBrowserStateFromUserIdMap(browser_state);
+  g_user_id_to_browser_state.Get()[new_id] = browser_state;
+  browser_state->SetUserData(kServiceUserId,
+                             base::MakeUnique<ServiceUserIdHolder>(new_id));
+
+  browser_state->SetUserData(kMojoWasInitialized,
+                             base::MakeUnique<base::SupportsUserData::Data>());
+
+  ServiceManagerConnection* service_manager_connection =
+      ServiceManagerConnection::Get();
+  if (service_manager_connection && base::ThreadTaskRunnerHandle::IsSet()) {
+    // NOTE: Many unit tests create a TestBrowserState without initializing
+    // Mojo or the global service manager connection.
+
+    // Have the global service manager connection start an instance of the
+    // web_browser service that is associated with this BrowserState (via
+    // |new_id|).
+    service_manager::mojom::ServicePtr service;
+    auto service_request = mojo::MakeRequest(&service);
+
+    service_manager::mojom::PIDReceiverPtr pid_receiver;
+    service_manager::Identity identity(mojom::kBrowserServiceName, new_id);
+    service_manager_connection->GetConnector()->StartService(
+        identity, std::move(service), mojo::MakeRequest(&pid_receiver));
+    pid_receiver->SetPID(base::GetCurrentProcId());
+
+    service_manager_connection->GetConnector()->StartService(identity);
+    auto connection_holder =
+        base::MakeUnique<BrowserStateServiceManagerConnectionHolder>(
+            std::move(service_request));
+
+    ServiceManagerConnection* connection =
+        connection_holder->service_manager_connection();
+
+    browser_state->SetUserData(kServiceManagerConnection,
+                               std::move(connection_holder));
+
+    // New embedded service factories should be added to |connection| here.
+    WebClient::StaticServiceMap services;
+    browser_state->RegisterServices(&services);
+    for (const auto& entry : services) {
+      connection->AddEmbeddedService(entry.first, entry.second);
+    }
+
+    connection->Start();
+  }
+}
+
+// static
+const std::string& BrowserState::GetServiceUserIdFor(
+    BrowserState* browser_state) {
+  CHECK(browser_state->GetUserData(kMojoWasInitialized))
+      << "Attempting to get the mojo user id for a BrowserState that was "
+      << "never Initialize()ed.";
+
+  ServiceUserIdHolder* holder = static_cast<ServiceUserIdHolder*>(
+      browser_state->GetUserData(kServiceUserId));
+  return holder->user_id();
+}
+
+// static
+service_manager::Connector* BrowserState::GetConnectorFor(
+    BrowserState* browser_state) {
+  ServiceManagerConnection* connection =
+      GetServiceManagerConnectionFor(browser_state);
+  return connection ? connection->GetConnector() : nullptr;
+}
+
+// static
+ServiceManagerConnection* BrowserState::GetServiceManagerConnectionFor(
+    BrowserState* browser_state) {
+  BrowserStateServiceManagerConnectionHolder* connection_holder =
+      static_cast<BrowserStateServiceManagerConnectionHolder*>(
+          browser_state->GetUserData(kServiceManagerConnection));
+  return connection_holder ? connection_holder->service_manager_connection()
+                           : nullptr;
+}
+
 }  // namespace web
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/app/mojo/web_browser_manifest.json b/ios/web/public/app/mojo/web_browser_manifest.json
index d2022fea..7b1f690 100644
--- a/ios/web/public/app/mojo/web_browser_manifest.json
+++ b/ios/web/public/app/mojo/web_browser_manifest.json
@@ -4,6 +4,9 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
+        "service_manager:service_factory": [
+          "service_manager::mojom::ServiceFactory"
+        ]
       },
       "requires": {
         "*": [ "app" ],
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index 73bc95d3..e5571a1 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -6,6 +6,7 @@
 #define IOS_WEB_PUBLIC_BROWSER_STATE_H_
 
 #include "base/supports_user_data.h"
+#include "services/service_manager/embedder/embedded_service_info.h"
 
 namespace base {
 class FilePath;
@@ -15,9 +16,14 @@
 class URLRequestContextGetter;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace web {
 class ActiveStateManager;
 class CertificatePolicyCache;
+class ServiceManagerConnection;
 class URLDataManagerIOS;
 class URLDataManagerIOSBackend;
 class URLRequestChromeJob;
@@ -60,9 +66,37 @@
   static BrowserState* FromSupportsUserData(
       base::SupportsUserData* supports_user_data);
 
+  // Returns a Service User ID associated with this BrowserState. This ID is
+  // not persistent across runs. See
+  // services/service_manager/public/interfaces/connector.mojom. By default,
+  // this user id is randomly generated when Initialize() is called.
+  static const std::string& GetServiceUserIdFor(BrowserState* browser_state);
+
+  // Returns a Connector associated with this BrowserState, which can be used
+  // to connect to service instances bound as this user.
+  static service_manager::Connector* GetConnectorFor(
+      BrowserState* browser_state);
+
+  // Returns a ServiceManagerConnection associated with this BrowserState,
+  // which can be used to connect to service instances bound as this user.
+  static ServiceManagerConnection* GetServiceManagerConnectionFor(
+      BrowserState* browser_state);
+
+  using StaticServiceMap =
+      std::map<std::string, service_manager::EmbeddedServiceInfo>;
+
+  // Registers per-browser-state services to be loaded by the Service Manager.
+  virtual void RegisterServices(StaticServiceMap* services) {}
+
  protected:
   BrowserState();
 
+  // Makes the Service Manager aware of this BrowserState, and assigns a user
+  // ID number to it. Must be called for each BrowserState created. |path|
+  // should be the same path that would be returned by GetStatePath().
+  static void Initialize(BrowserState* browser_state,
+                         const base::FilePath& path);
+
  private:
   friend class URLDataManagerIOS;
   friend class URLRequestChromeJob;
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/public/test/fakes/test_browser_state.cc b/ios/web/public/test/fakes/test_browser_state.cc
index e6f1591..7cd4343 100644
--- a/ios/web/public/test/fakes/test_browser_state.cc
+++ b/ios/web/public/test/fakes/test_browser_state.cc
@@ -43,7 +43,9 @@
 
 }  // namespace
 
-TestBrowserState::TestBrowserState() : is_off_the_record_(false) {}
+TestBrowserState::TestBrowserState() : is_off_the_record_(false) {
+  BrowserState::Initialize(this, GetStatePath());
+}
 
 TestBrowserState::~TestBrowserState() {}
 
diff --git a/ios/web/service_manager_connection_impl.cc b/ios/web/service_manager_connection_impl.cc
index 1ff842a..9fdf4e0d 100644
--- a/ios/web/service_manager_connection_impl.cc
+++ b/ios/web/service_manager_connection_impl.cc
@@ -268,7 +268,11 @@
 
 // static
 ServiceManagerConnection* ServiceManagerConnection::Get() {
-  DCHECK_CURRENTLY_ON(WebThread::UI);
+  // WebThreads are not initialized in many unit tests. These tests also by
+  // definition are not setting the global ServiceManagerConnection (since
+  // otherwise the DCHECK in the above method would fire).
+  DCHECK(!web::WebThread::IsThreadInitialized(web::WebThread::UI) ||
+         web::WebThread::CurrentlyOn(web::WebThread::UI));
   return g_connection_for_process.Get().get();
 }
 
diff --git a/ios/web/shell/BUILD.gn b/ios/web/shell/BUILD.gn
index f8332d92..c29eca4 100644
--- a/ios/web/shell/BUILD.gn
+++ b/ios/web/shell/BUILD.gn
@@ -44,6 +44,7 @@
 
 service_manifest("shell_browser_manifest_overlay") {
   source = "web_shell_browser_manifest_overlay.json"
+  packaged_services = [ "//services/test/user_id:manifest" ]
 }
 
 grit("resources") {
@@ -112,6 +113,8 @@
     "//net:extras",
     "//services/test/echo:lib",
     "//services/test/echo/public/interfaces",
+    "//services/test/user_id:lib",
+    "//services/test/user_id/public/interfaces",
     "//ui/base",
   ]
 
diff --git a/ios/web/shell/DEPS b/ios/web/shell/DEPS
index 2ab608b..7e84e870 100644
--- a/ios/web/shell/DEPS
+++ b/ios/web/shell/DEPS
@@ -4,5 +4,6 @@
   "+ios/web/public",
   "+ios/web/shell",
   "+services/test/echo",
+  "+services/test/user_id",
 ]
 
diff --git a/ios/web/shell/shell_browser_state.h b/ios/web/shell/shell_browser_state.h
index 045911a..cc69fdb7 100644
--- a/ios/web/shell/shell_browser_state.h
+++ b/ios/web/shell/shell_browser_state.h
@@ -25,6 +25,7 @@
   bool IsOffTheRecord() const override;
   base::FilePath GetStatePath() const override;
   net::URLRequestContextGetter* GetRequestContext() override;
+  void RegisterServices(StaticServiceMap* services) override;
 
  private:
   base::FilePath path_;
diff --git a/ios/web/shell/shell_browser_state.mm b/ios/web/shell/shell_browser_state.mm
index be4fc4c..f954750 100644
--- a/ios/web/shell/shell_browser_state.mm
+++ b/ios/web/shell/shell_browser_state.mm
@@ -11,6 +11,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "ios/web/public/web_thread.h"
 #include "ios/web/shell/shell_url_request_context_getter.h"
+#include "services/test/user_id/user_id_service.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -26,6 +27,8 @@
       web::WebThread::GetTaskRunnerForThread(web::WebThread::IO),
       web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
       web::WebThread::GetTaskRunnerForThread(web::WebThread::CACHE));
+
+  BrowserState::Initialize(this, path_);
 }
 
 ShellBrowserState::~ShellBrowserState() {
@@ -43,4 +46,11 @@
   return request_context_getter_.get();
 }
 
+void ShellBrowserState::RegisterServices(StaticServiceMap* services) {
+  service_manager::EmbeddedServiceInfo user_id_info;
+  user_id_info.factory = base::Bind(&user_id::CreateUserIdService);
+  user_id_info.task_runner = base::ThreadTaskRunnerHandle::Get();
+  services->insert(std::make_pair("user_id", user_id_info));
+}
+
 }  // namespace web
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn
index 4cdbb66..3a82cd9 100644
--- a/ios/web/shell/test/BUILD.gn
+++ b/ios/web/shell/test/BUILD.gn
@@ -40,6 +40,7 @@
     "//net",
     "//services/service_manager/public/cpp",
     "//services/test/echo/public/interfaces",
+    "//services/test/user_id/public/interfaces",
     "//url",
 
     # All shared libraries must have the sanitizer deps to properly link in
diff --git a/ios/web/shell/test/service_manager_egtest.mm b/ios/web/shell/test/service_manager_egtest.mm
index 4a181e4..38bc933 100644
--- a/ios/web/shell/test/service_manager_egtest.mm
+++ b/ios/web/shell/test/service_manager_egtest.mm
@@ -7,11 +7,14 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #import "ios/testing/wait_util.h"
+#include "ios/web/public/browser_state.h"
 #include "ios/web/public/service_manager_connection.h"
+#import "ios/web/shell/test/app/web_shell_test_util.h"
 #import "ios/web/shell/test/earl_grey/shell_earl_grey.h"
 #import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/test/echo/public/interfaces/echo.mojom.h"
+#include "services/test/user_id/public/interfaces/user_id.mojom.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -34,16 +37,33 @@
   *echo_callback_called_flag = true;
 }
 
-// Waits until the callback to echo::mojom::Echo::EchoString() is invoked (as
-// signalled by that callback setting |echo_callback_called_flag| to true).
-void WaitForEchoStringCallback(bool* echo_callback_called_flag) {
+// Callback passed to user_id::mojom::UserId::GetUserId(). Verifies that the
+// passed-back user ID has the expected value and sets
+// |user_id_callback_called_flag| to true to indicate that the callback was
+// invoked. |user_id| is passed simply to ensure that our connection to the
+// UserId implementation remains alive long enough for the callback to reach
+// us.
+void OnGotUserId(user_id::mojom::UserIdPtr user_id,
+                 bool* user_id_callback_called_flag,
+                 const std::string& expected_user_id,
+                 const std::string& received_user_id) {
+  GREYAssert(expected_user_id == received_user_id,
+             @"Unexpected User ID passed to user_id callback: %s",
+             received_user_id.c_str());
+  *user_id_callback_called_flag = true;
+}
+
+// Waits until a given callback is invoked (as signalled by that callback
+// setting |callback_called_flag| to true).
+void WaitForCallback(const std::string& callback_name,
+                     bool* callback_called_flag) {
   GREYCondition* condition =
-      [GREYCondition conditionWithName:@"Wait for echo string callback"
+      [GREYCondition conditionWithName:@"Wait for callback"
                                  block:^BOOL {
-                                   return *echo_callback_called_flag;
+                                   return *callback_called_flag;
                                  }];
   GREYAssert([condition waitWithTimeout:testing::kWaitForUIElementTimeout],
-             @"Failed waiting for echo callback");
+             @"Failed waiting for %s callback", callback_name.c_str());
 }
 }
 
@@ -53,9 +73,9 @@
 
 @implementation ServiceManagerTestCase
 
-// Tests that it is possible to connect to an embedded service that was
-// registered by web_shell.
-- (void)testConnectionToEmbeddedService {
+// Tests that it is possible to connect to an all-users embedded service that
+// was registered by web_shell.
+- (void)testConnectionToAllUsersEmbeddedService {
   // Connect to the echo service and bind an Echo instance.
   echo::mojom::EchoPtr echo;
   web::ServiceManagerConnection* connection =
@@ -65,13 +85,33 @@
 
   // Call EchoString, making sure to keep our end of the connection alive
   // until the callback is received.
-  echo::mojom::Echo* raw_echo = echo.get();
-  bool echo_callback_called = false;
-  raw_echo->EchoString(kTestInput,
-                       base::BindOnce(&OnEchoString, base::Passed(&echo),
-                                      &echo_callback_called));
+  echo::mojom::Echo* rawEcho = echo.get();
+  bool echoCallbackCalled = false;
+  rawEcho->EchoString(
+      kTestInput,
+      base::BindOnce(&OnEchoString, base::Passed(&echo), &echoCallbackCalled));
 
-  WaitForEchoStringCallback(&echo_callback_called);
+  WaitForCallback("EchoString", &echoCallbackCalled);
+}
+
+// Tests that it is possible to connect to a per-user embedded service that
+// was registered by web_shell.
+- (void)testConnectionToPerUserEmbeddedService {
+  // Connect to the user ID service and bind a UserId instance.
+  user_id::mojom::UserIdPtr userID;
+  web::WebState* webState = web::shell_test_util::GetCurrentWebState();
+  web::BrowserState::GetConnectorFor(webState->GetBrowserState())
+      ->BindInterface("user_id", mojo::MakeRequest(&userID));
+
+  // Call GetUserId(), making sure to keep our end of the connection alive
+  // until the callback is received.
+  user_id::mojom::UserId* rawUserID = userID.get();
+  bool userIDCallbackCalled = false;
+  rawUserID->GetUserId(base::BindOnce(
+      &OnGotUserId, base::Passed(&userID), &userIDCallbackCalled,
+      web::BrowserState::GetServiceUserIdFor(webState->GetBrowserState())));
+
+  WaitForCallback("GetUserId", &userIDCallbackCalled);
 }
 
 @end
diff --git a/ios/web/shell/web_shell_browser_manifest_overlay.json b/ios/web/shell/web_shell_browser_manifest_overlay.json
index 9bb8809..ac88963 100644
--- a/ios/web/shell/web_shell_browser_manifest_overlay.json
+++ b/ios/web/shell/web_shell_browser_manifest_overlay.json
@@ -3,7 +3,8 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "requires": {
-        "echo": [ "echo" ]
+        "echo": [ "echo" ],
+        "user_id": [ "user_id" ]
       }
     }
   }
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..28f53e3 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"
@@ -48,6 +50,8 @@
       web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
       web::WebThread::GetTaskRunnerForThread(web::WebThread::CACHE));
 
+  BrowserState::Initialize(this, path_);
+
   // Initialize prefs.
   scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry =
       new user_prefs::PrefRegistrySyncable;
@@ -56,8 +60,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/mash/task_viewer/task_viewer.cc b/mash/task_viewer/task_viewer.cc
index d932576..b4ef1fd 100644
--- a/mash/task_viewer/task_viewer.cc
+++ b/mash/task_viewer/task_viewer.cc
@@ -203,6 +203,8 @@
     }
     NOTREACHED();
   }
+  void OnServicePIDReceived(const service_manager::Identity& identity,
+                            uint32_t pid) override {}
 
   bool ContainsIdentity(const service_manager::Identity& identity) const {
     for (auto& it : instances_) {
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 5932ac73..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/BUILD.gn b/media/mojo/interfaces/BUILD.gn
index ad90949..acfa3fc 100644
--- a/media/mojo/interfaces/BUILD.gn
+++ b/media/mojo/interfaces/BUILD.gn
@@ -20,6 +20,7 @@
     "provision_fetcher.mojom",
     "renderer.mojom",
     "video_decoder.mojom",
+    "video_encode_accelerator.mojom",
   ]
 
   if (is_android) {
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/interfaces/video_encode_accelerator.mojom b/media/mojo/interfaces/video_encode_accelerator.mojom
new file mode 100644
index 0000000..55e20c7
--- /dev/null
+++ b/media/mojo/interfaces/video_encode_accelerator.mojom
@@ -0,0 +1,8 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module media.mojom;
+
+// TODO(mcasas): Finalize migrating the IPC messages https://crbug.com/736517.
+interface VideoEncodeAccelerator{};
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/mojo/common/BUILD.gn b/mojo/common/BUILD.gn
index 1bf62d22..a537e1d 100644
--- a/mojo/common/BUILD.gn
+++ b/mojo/common/BUILD.gn
@@ -57,9 +57,6 @@
   public_deps = [
     ":common_custom_types",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
 
 test("mojo_common_unittests") {
diff --git a/mojo/common/common_custom_types_unittest.cc b/mojo/common/common_custom_types_unittest.cc
index fd0cad1..988ca61 100644
--- a/mojo/common/common_custom_types_unittest.cc
+++ b/mojo/common/common_custom_types_unittest.cc
@@ -71,8 +71,8 @@
 
   // TestFilePath implementation:
   void BounceFilePath(const base::FilePath& in,
-                      const BounceFilePathCallback& callback) override {
-    callback.Run(in);
+                      BounceFilePathCallback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
@@ -86,8 +86,8 @@
 
   // TestUnguessableToken implementation:
   void BounceNonce(const base::UnguessableToken& in,
-                   const BounceNonceCallback& callback) override {
-    callback.Run(in);
+                   BounceNonceCallback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
@@ -100,18 +100,18 @@
       : binding_(this, std::move(request)) {}
 
   // TestTime implementation:
-  void BounceTime(base::Time in, const BounceTimeCallback& callback) override {
-    callback.Run(in);
+  void BounceTime(base::Time in, BounceTimeCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceTimeDelta(base::TimeDelta in,
-                       const BounceTimeDeltaCallback& callback) override {
-    callback.Run(in);
+                       BounceTimeDeltaCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   void BounceTimeTicks(base::TimeTicks in,
-                       const BounceTimeTicksCallback& callback) override {
-    callback.Run(in);
+                       BounceTimeTicksCallback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
@@ -124,20 +124,19 @@
       : binding_(this, std::move(request)) {}
 
   // TestValue implementation:
-  void BounceDictionaryValue(
-      std::unique_ptr<base::DictionaryValue> in,
-      const BounceDictionaryValueCallback& callback) override {
-    callback.Run(std::move(in));
+  void BounceDictionaryValue(std::unique_ptr<base::DictionaryValue> in,
+                             BounceDictionaryValueCallback callback) override {
+    std::move(callback).Run(std::move(in));
   }
 
   void BounceListValue(std::unique_ptr<base::ListValue> in,
-                       const BounceListValueCallback& callback) override {
-    callback.Run(std::move(in));
+                       BounceListValueCallback callback) override {
+    std::move(callback).Run(std::move(in));
   }
 
   void BounceValue(std::unique_ptr<base::Value> in,
-                   const BounceValueCallback& callback) override {
-    callback.Run(std::move(in));
+                   BounceValueCallback callback) override {
+    std::move(callback).Run(std::move(in));
   }
 
  private:
@@ -151,8 +150,8 @@
 
   // TestString16 implementation:
   void BounceString16(const base::string16& in,
-                      const BounceString16Callback& callback) override {
-    callback.Run(in);
+                      BounceString16Callback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
@@ -165,8 +164,8 @@
       : binding_(this, std::move(request)) {}
 
   // TestFile implementation:
-  void BounceFile(base::File in, const BounceFileCallback& callback) override {
-    callback.Run(std::move(in));
+  void BounceFile(base::File in, BounceFileCallback callback) override {
+    std::move(callback).Run(std::move(in));
   }
 
  private:
@@ -179,10 +178,9 @@
       : binding_(this, std::move(request)) {}
 
   // TestTextDirection:
-  void BounceTextDirection(
-      base::i18n::TextDirection in,
-      const BounceTextDirectionCallback& callback) override {
-    callback.Run(in);
+  void BounceTextDirection(base::i18n::TextDirection in,
+                           BounceTextDirectionCallback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
diff --git a/mojo/common/struct_traits_unittest.cc b/mojo/common/struct_traits_unittest.cc
index 52c49e0..8956aea 100644
--- a/mojo/common/struct_traits_unittest.cc
+++ b/mojo/common/struct_traits_unittest.cc
@@ -25,8 +25,8 @@
  private:
   // TraitsTestService:
   void EchoVersion(const base::Optional<base::Version>& m,
-                   const EchoVersionCallback& callback) override {
-    callback.Run(m);
+                   EchoVersionCallback callback) override {
+    std::move(callback).Run(m);
   }
 
   base::MessageLoop loop_;
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_net_fetcher.h b/net/cert/cert_net_fetcher.h
index 2a45fe3..376e4a83 100644
--- a/net/cert/cert_net_fetcher.h
+++ b/net/cert/cert_net_fetcher.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <vector>
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_export.h"
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/internal/cert_error_params.cc b/net/cert/internal/cert_error_params.cc
index 29730602..d9fae76 100644
--- a/net/cert/internal/cert_error_params.cc
+++ b/net/cert/internal/cert_error_params.cc
@@ -4,6 +4,7 @@
 
 #include "net/cert/internal/cert_error_params.h"
 
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/der/input.h"
diff --git a/net/cert/internal/cert_issuer_source_aia.cc b/net/cert/internal/cert_issuer_source_aia.cc
index 8ddb9a00a..aa472595 100644
--- a/net/cert/internal/cert_issuer_source_aia.cc
+++ b/net/cert/internal/cert_issuer_source_aia.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/internal/cert_issuer_source_aia.h"
 
-#include "base/bind.h"
 #include "net/cert/cert_net_fetcher.h"
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/x509_util.h"
diff --git a/net/cert/internal/cert_issuer_source_aia_unittest.cc b/net/cert/internal/cert_issuer_source_aia_unittest.cc
index b332dee..ba9ff0f 100644
--- a/net/cert/internal/cert_issuer_source_aia_unittest.cc
+++ b/net/cert/internal/cert_issuer_source_aia_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/internal/cert_issuer_source_aia.h"
 
-#include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "net/cert/cert_net_fetcher.h"
 #include "net/cert/internal/cert_errors.h"
diff --git a/net/cert/internal/name_constraints.cc b/net/cert/internal/name_constraints.cc
index d9329803..f3dbbee7 100644
--- a/net/cert/internal/name_constraints.cc
+++ b/net/cert/internal/name_constraints.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "net/cert/internal/verify_name_match.h"
 #include "net/der/input.h"
diff --git a/net/cert/internal/name_constraints_unittest.cc b/net/cert/internal/name_constraints_unittest.cc
index 150d851c..a24860c 100644
--- a/net/cert/internal/name_constraints_unittest.cc
+++ b/net/cert/internal/name_constraints_unittest.cc
@@ -8,12 +8,9 @@
 
 #include "net/base/ip_address.h"
 #include "net/cert/internal/test_helpers.h"
-#include "net/test/gtest_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using net::test::IsOk;
-
 namespace net {
 namespace {
 
diff --git a/net/cert/internal/parse_name.cc b/net/cert/internal/parse_name.cc
index f3aa518f..4a9a544b 100644
--- a/net/cert/internal/parse_name.cc
+++ b/net/cert/internal/parse_name.cc
@@ -4,7 +4,6 @@
 
 #include "net/cert/internal/parse_name.h"
 
-#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversion_utils.h"
diff --git a/net/cert/internal/parse_ocsp.h b/net/cert/internal/parse_ocsp.h
index 7fc1d5a..e1c270c2 100644
--- a/net/cert/internal/parse_ocsp.h
+++ b/net/cert/internal/parse_ocsp.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/time/time.h"
 #include "net/base/net_export.h"
 #include "net/cert/internal/parse_certificate.h"
 #include "net/cert/internal/signature_algorithm.h"
diff --git a/net/cert/internal/parse_ocsp_unittest.cc b/net/cert/internal/parse_ocsp_unittest.cc
index 08e18db..c3ad815 100644
--- a/net/cert/internal/parse_ocsp_unittest.cc
+++ b/net/cert/internal/parse_ocsp_unittest.cc
@@ -4,12 +4,9 @@
 
 #include "net/cert/internal/parse_ocsp.h"
 
-#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "net/cert/internal/test_helpers.h"
-#include "net/cert/x509_certificate.h"
 #include "net/der/encode_values.h"
-#include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/cert/internal/parsed_certificate.h b/net/cert/internal/parsed_certificate.h
index 69741eb..7afb27e 100644
--- a/net/cert/internal/parsed_certificate.h
+++ b/net/cert/internal/parsed_certificate.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
 #include "net/cert/internal/certificate_policies.h"
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc
index c09504da..5035ac6 100644
--- a/net/cert/internal/path_builder_unittest.cc
+++ b/net/cert/internal/path_builder_unittest.cc
@@ -16,7 +16,6 @@
 #include "net/cert/internal/verify_certificate_chain.h"
 #include "net/cert/pem_tokenizer.h"
 #include "net/der/input.h"
-#include "net/test/cert_test_util.h"
 #include "net/test/test_certificate_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/cert/internal/signature_algorithm_unittest.cc b/net/cert/internal/signature_algorithm_unittest.cc
index 5688cc0..679b981 100644
--- a/net/cert/internal/signature_algorithm_unittest.cc
+++ b/net/cert/internal/signature_algorithm_unittest.cc
@@ -12,7 +12,6 @@
 #include "net/cert/pem_tokenizer.h"
 #include "net/der/input.h"
 #include "net/der/parser.h"
-#include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/cert/internal/verify_name_match.cc b/net/cert/internal/verify_name_match.cc
index b999355b..0b6ab81 100644
--- a/net/cert/internal/verify_name_match.cc
+++ b/net/cert/internal/verify_name_match.cc
@@ -7,8 +7,8 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "base/tuple.h"
 #include "net/cert/internal/parse_name.h"
 #include "net/der/input.h"
 #include "net/der/parser.h"
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/der/parser.cc b/net/der/parser.cc
index 7b8273d4..023f47a6 100644
--- a/net/der/parser.cc
+++ b/net/der/parser.cc
@@ -4,6 +4,7 @@
 
 #include "net/der/parser.h"
 
+#include "base/logging.h"
 #include "net/der/parse_values.h"
 
 namespace net {
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/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index d165dd6..872a613b 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -253,8 +253,7 @@
   clients_.push_back(base::MakeUnique<ClientSession>(
       this, std::move(connection), desktop_environment_factory_,
       desktop_environment_options_, max_session_duration_, pairing_registry_,
-      extension_ptrs,
-      std::vector<protocol::DataChannelManager::NameCallbackPair>()));
+      extension_ptrs));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc
index d8519e8..a8a8f66 100644
--- a/remoting/host/chromoting_host_unittest.cc
+++ b/remoting/host/chromoting_host_unittest.cc
@@ -132,8 +132,7 @@
     std::unique_ptr<ClientSession> client(new ClientSession(
         host_.get(), std::move(connection), desktop_environment_factory_.get(),
         DesktopEnvironmentOptions::CreateDefault(), base::TimeDelta(), nullptr,
-        std::vector<HostExtension*>(),
-        std::vector<protocol::DataChannelManager::NameCallbackPair>()));
+        std::vector<HostExtension*>()));
     ClientSession* client_ptr = client.get();
 
     connection_ptr->set_host_stub(client.get());
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index b9877821..93d6440f 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -49,9 +49,7 @@
     const DesktopEnvironmentOptions& desktop_environment_options,
     const base::TimeDelta& max_duration,
     scoped_refptr<protocol::PairingRegistry> pairing_registry,
-    const std::vector<HostExtension*>& extensions,
-    const std::vector<protocol::DataChannelManager::NameCallbackPair>&
-        data_channel_callbacks)
+    const std::vector<HostExtension*>& extensions)
     : event_handler_(event_handler),
       connection_(std::move(connection)),
       client_jid_(connection_->session()->jid()),
@@ -76,11 +74,6 @@
   // Create a manager for the configured extensions, if any.
   extension_manager_.reset(new HostExtensionSessionManager(extensions, this));
 
-  for (const auto& callback : data_channel_callbacks) {
-    data_channel_manager_.RegisterCreateHandlerCallback(callback.first,
-                                                        callback.second);
-  }
-
 #if defined(OS_WIN)
   // LocalInputMonitorWin filters out an echo of the injected input before it
   // reaches |remote_input_filter_|.
@@ -416,6 +409,13 @@
   return this;
 }
 
+void ClientSession::RegisterCreateHandlerCallbackForTesting(
+    const std::string& prefix,
+    protocol::DataChannelManager::CreateHandlerCallback constructor) {
+  data_channel_manager_.RegisterCreateHandlerCallback(
+      prefix, std::move(constructor));
+}
+
 void ClientSession::SetEventTimestampsSourceForTests(
     scoped_refptr<protocol::InputEventTimestampsSource>
         event_timestamp_source) {
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h
index d0c830b..c439355b 100644
--- a/remoting/host/client_session.h
+++ b/remoting/host/client_session.h
@@ -97,9 +97,7 @@
       const DesktopEnvironmentOptions& desktop_environment_options,
       const base::TimeDelta& max_duration,
       scoped_refptr<protocol::PairingRegistry> pairing_registry,
-      const std::vector<HostExtension*>& extensions,
-      const std::vector<protocol::DataChannelManager::NameCallbackPair>&
-          data_channel_callbacks);
+      const std::vector<HostExtension*>& extensions);
   ~ClientSession() override;
 
   // Returns the set of capabilities negotiated between client and host.
@@ -145,6 +143,11 @@
     return client_capabilities_.get();
   }
 
+  // Registers a DataChannelManager callback for testing.
+  void RegisterCreateHandlerCallbackForTesting(
+      const std::string& prefix,
+      protocol::DataChannelManager::CreateHandlerCallback constructor);
+
   void SetEventTimestampsSourceForTests(
       scoped_refptr<protocol::InputEventTimestampsSource>
           event_timestamp_source);
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index 7530800..0bd7b35 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -135,9 +135,6 @@
   // ownership of the HostExtensions themselves.
   std::vector<HostExtension*> extensions_;
 
-  std::vector<protocol::DataChannelManager::NameCallbackPair>
-      data_channel_callbacks_;
-
   // ClientSession instance under test.
   std::unique_ptr<ClientSession> client_session_;
 
@@ -190,7 +187,7 @@
       &session_event_handler_, std::move(connection),
       desktop_environment_factory_.get(),
       DesktopEnvironmentOptions::CreateDefault(), base::TimeDelta(), nullptr,
-      extensions_, data_channel_callbacks_));
+      extensions_));
 }
 
 void ClientSessionTest::CreateClientSession() {
@@ -438,15 +435,13 @@
 TEST_F(ClientSessionTest, DataChannelCallbackIsCalled) {
   bool callback_called = false;
 
-  data_channel_callbacks_.push_back(
-      protocol::DataChannelManager::NameCallbackPair(
-          kTestDataChannelCallbackName,
-          base::Bind([](bool* callback_was_called, const std::string& name,
-                        std::unique_ptr<protocol::MessagePipe> pipe)
-                         -> void { *callback_was_called = true; },
-                     &callback_called)));
-
   CreateClientSession();
+  client_session_->RegisterCreateHandlerCallbackForTesting(
+      kTestDataChannelCallbackName,
+      base::Bind([](bool* callback_was_called, const std::string& name,
+                    std::unique_ptr<protocol::MessagePipe> pipe)
+                     -> void { *callback_was_called = true; },
+                 &callback_called));
   ConnectClientSession();
 
   std::unique_ptr<protocol::MessagePipe> pipe =
diff --git a/remoting/ios/app/BUILD.gn b/remoting/ios/app/BUILD.gn
index 6b442a6e..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/remoting_ios_tmpl.gni b/remoting/ios/app/remoting_ios_tmpl.gni
index 88113df..2711e01 100644
--- a/remoting/ios/app/remoting_ios_tmpl.gni
+++ b/remoting/ios/app/remoting_ios_tmpl.gni
@@ -56,9 +56,9 @@
     extra_substitutions = [
       "BUNDLE_IDENTIFIER=$bundle_id",
       "DISPLAY_NAME=$remoting_ios_display_name",
-      "EXECUTABLE_NAME=$remoting_ios_executable_name",
+      "EXECUTABLE_NAME=$output_name",
       "MINIMUM_OS_VERSION=7.0",
-      "PRODUCT_NAME=$remoting_ios_product_name",
+      "PRODUCT_NAME=$output_name",
       "VERSION_FULL=$remoting_version_full",
       "VERSION_SHORT=$remoting_version_short",
     ]
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/remoting/protocol/data_channel_manager.cc b/remoting/protocol/data_channel_manager.cc
index c8f0782..aa2914ed 100644
--- a/remoting/protocol/data_channel_manager.cc
+++ b/remoting/protocol/data_channel_manager.cc
@@ -20,7 +20,7 @@
     CreateHandlerCallback constructor) {
   DCHECK(!prefix.empty());
   DCHECK(constructor);
-  constructors_.push_back(std::make_pair(prefix, constructor));
+  constructors_.push_back(std::make_pair(prefix, std::move(constructor)));
 }
 
 bool DataChannelManager::OnIncomingDataChannel(
diff --git a/remoting/protocol/data_channel_manager.h b/remoting/protocol/data_channel_manager.h
index dfe3a08..32b0198 100644
--- a/remoting/protocol/data_channel_manager.h
+++ b/remoting/protocol/data_channel_manager.h
@@ -24,8 +24,6 @@
       const std::string& name,
       std::unique_ptr<MessagePipe> pipe)>;
 
-  using NameCallbackPair = std::pair<std::string, CreateHandlerCallback>;
-
   DataChannelManager();
   ~DataChannelManager();
 
@@ -40,7 +38,7 @@
                              std::unique_ptr<MessagePipe> pipe);
 
  private:
-  std::vector<NameCallbackPair> constructors_;
+  std::vector<std::pair<std::string, CreateHandlerCallback>> constructors_;
 };
 
 }  // namespace protocol
diff --git a/remoting/test/it2me_standalone_host.cc b/remoting/test/it2me_standalone_host.cc
index 82de866..eed5c913 100644
--- a/remoting/test/it2me_standalone_host.cc
+++ b/remoting/test/it2me_standalone_host.cc
@@ -90,8 +90,8 @@
   session_.reset(new ClientSession(
       &handler_, std::unique_ptr<protocol::ConnectionToClient>(&connection_),
       &factory_, options, base::TimeDelta(),
-      scoped_refptr<protocol::PairingRegistry>(), std::vector<HostExtension*>(),
-      std::vector<protocol::DataChannelManager::NameCallbackPair>()));
+      scoped_refptr<protocol::PairingRegistry>(),
+      std::vector<HostExtension*>()));
   session_->OnConnectionAuthenticated();
   session_->OnConnectionChannelsConnected();
   session_->CreateMediaStreams();
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 82dab43a..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/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h
index ef1802f..fcefa5b 100644
--- a/services/metrics/public/cpp/ukm_recorder.h
+++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -20,7 +20,6 @@
 
 class ContextualSearchRankerLoggerImpl;
 class PluginInfoMessageFilter;
-class ProcessMemoryMetricsEmitter;
 class UkmPageLoadMetricsObserver;
 class LocalNetworkRequestsPageLoadMetricsObserver;
 
@@ -90,7 +89,6 @@
   friend autofill::AutofillMetrics;
   friend payments::JourneyLogger;
   friend ContextualSearchRankerLoggerImpl;
-  friend ProcessMemoryMetricsEmitter;
   friend PluginInfoMessageFilter;
   friend UkmPageLoadMetricsObserver;
   friend LocalNetworkRequestsPageLoadMetricsObserver;
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index 8c02a1c..0489f89 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -78,6 +78,7 @@
     "memory_instrumentation/process_map_unittest.cc",
     "public/cpp/memory_instrumentation/os_metrics_unittest.cc",
     "public/cpp/memory_instrumentation/process_metrics_memory_dump_provider_unittest.cc",
+    "public/cpp/memory_instrumentation/tracing_integration_unittest.cc",
     "public/cpp/tracing/chrome_trace_event_agent_unittest.cc",
     "tracing/agent_registry_unittest.cc",
     "tracing/coordinator_unittest.cc",
diff --git a/services/resource_coordinator/memory_instrumentation/process_map.cc b/services/resource_coordinator/memory_instrumentation/process_map.cc
index 3e39329..cd2fe1b 100644
--- a/services/resource_coordinator/memory_instrumentation/process_map.cc
+++ b/services/resource_coordinator/memory_instrumentation/process_map.cc
@@ -55,6 +55,9 @@
   instances_.erase(identity);
 }
 
+void ProcessMap::OnServicePIDReceived(const service_manager::Identity& identity,
+                                      uint32_t pid) {}
+
 base::ProcessId ProcessMap::GetProcessId(
     const service_manager::Identity& identity) const {
   auto it = instances_.find(identity);
diff --git a/services/resource_coordinator/memory_instrumentation/process_map.h b/services/resource_coordinator/memory_instrumentation/process_map.h
index f5d1521..d130681 100644
--- a/services/resource_coordinator/memory_instrumentation/process_map.h
+++ b/services/resource_coordinator/memory_instrumentation/process_map.h
@@ -50,6 +50,8 @@
   void OnServiceStarted(const Identity&, uint32_t pid) override;
   void OnServiceFailedToStart(const Identity&) override;
   void OnServiceStopped(const Identity&) override;
+  void OnServicePIDReceived(const service_manager::Identity& identity,
+                            uint32_t pid) override;
 
   mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_;
   std::map<Identity, base::ProcessId> instances_;
diff --git a/services/resource_coordinator/public/cpp/BUILD.gn b/services/resource_coordinator/public/cpp/BUILD.gn
index b98ca1a..fda46f13 100644
--- a/services/resource_coordinator/public/cpp/BUILD.gn
+++ b/services/resource_coordinator/public/cpp/BUILD.gn
@@ -12,7 +12,6 @@
     "memory_instrumentation/coordinator.h",
     "memory_instrumentation/memory_instrumentation.cc",
     "memory_instrumentation/memory_instrumentation.h",
-    "memory_instrumentation/os_metrics.cc",
     "memory_instrumentation/os_metrics.h",
     "memory_instrumentation/os_metrics_linux.cc",
     "memory_instrumentation/os_metrics_mac.cc",
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
index 46d62f8..1b323af 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
@@ -29,14 +29,23 @@
 
 ClientProcessImpl::ClientProcessImpl(const Config& config)
     : binding_(this), process_type_(config.process_type), task_runner_() {
-  config.connector->BindInterface(config.service_name,
-                                  mojo::MakeRequest(&coordinator_));
-  mojom::ClientProcessPtr process;
-  binding_.Bind(mojo::MakeRequest(&process));
-  coordinator_->RegisterClientProcess(std::move(process), config.process_type);
+  // |config.connector| can be null in tests.
+  if (config.connector) {
+    config.connector->BindInterface(config.service_name,
+                                    mojo::MakeRequest(&coordinator_));
+    mojom::ClientProcessPtr process;
+    binding_.Bind(mojo::MakeRequest(&process));
+    coordinator_->RegisterClientProcess(std::move(process),
+                                        config.process_type);
 
-  // Initialize the public-facing MemoryInstrumentation helper.
-  MemoryInstrumentation::CreateInstance(config.connector, config.service_name);
+    // Initialize the public-facing MemoryInstrumentation helper.
+    MemoryInstrumentation::CreateInstance(config.connector,
+                                          config.service_name);
+  } else {
+    config.coordinator_for_testing->BindCoordinatorRequest(
+        service_manager::BindSourceInfo(), mojo::MakeRequest(&coordinator_));
+  }
+
   task_runner_ = base::ThreadTaskRunnerHandle::Get();
 
   // TODO(primiano): this is a temporary workaround to tell the
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
index 0dfa344..c657cd8 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
@@ -37,6 +37,7 @@
     ~Config();
 
     service_manager::Connector* const connector;
+    Coordinator* coordinator_for_testing;
     const std::string service_name;
     const mojom::ProcessType process_type;
   };
@@ -45,7 +46,7 @@
 
  private:
   friend std::default_delete<ClientProcessImpl>;  // For testing
-  friend class ClientProcessImplTest;
+  friend class MemoryTracingIntegrationTest;
 
   ClientProcessImpl(const Config& config);
   ~ClientProcessImpl() override;
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.cc
deleted file mode 100644
index 6e4c92a..0000000
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
-
-namespace memory_instrumentation {
-
-mojom::RawOSMemDumpPtr GetOSMemoryDump(base::ProcessId pid) {
-  mojom::RawOSMemDumpPtr dump = mojom::RawOSMemDump::New();
-  FillOSMemoryDump(pid, dump.get());
-  return dump;
-}
-
-}  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
index 09e258ec..38a649b 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
@@ -5,15 +5,26 @@
 #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_OS_METRICS_H_
 
 #include "base/process/process_handle.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
 #include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
 
 namespace memory_instrumentation {
 
-mojom::RawOSMemDumpPtr SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
-GetOSMemoryDump(base::ProcessId pid);
+class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT OSMetrics {
+ public:
+  static bool FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump);
+  static bool FillProcessMemoryMaps(base::ProcessId,
+                                    base::trace_event::ProcessMemoryDump*);
 
-void FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump);
+ private:
+  FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  static void SetProcSmapsForTesting(FILE*);
+#endif  // defined(OS_LINUX)
+};
 
 }  // namespace memory_instrumentation
 
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
index e818bea..3a2d6947 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
@@ -11,6 +11,7 @@
 #include "base/format_macros.h"
 #include "base/process/process_metrics.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
@@ -52,14 +53,141 @@
   return base::ProcessMetrics::CreateProcessMetrics(pid);
 }
 
+bool ParseSmapsHeader(const char* header_line,
+                      base::trace_event::ProcessMemoryMaps::VMRegion* region) {
+  // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234  /foo.so\n"
+  bool res = true;  // Whether this region should be appended or skipped.
+  uint64_t end_addr = 0;
+  char protection_flags[5] = {0};
+  char mapped_file[kMaxLineSize];
+
+  if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n",
+             &region->start_address, &end_addr, protection_flags,
+             mapped_file) != 4)
+    return false;
+
+  if (end_addr > region->start_address) {
+    region->size_in_bytes = end_addr - region->start_address;
+  } else {
+    // This is not just paranoia, it can actually happen (See crbug.com/461237).
+    region->size_in_bytes = 0;
+    res = false;
+  }
+
+  region->protection_flags = 0;
+  if (protection_flags[0] == 'r') {
+    region->protection_flags |=
+        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  }
+  if (protection_flags[1] == 'w') {
+    region->protection_flags |=
+        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  }
+  if (protection_flags[2] == 'x') {
+    region->protection_flags |=
+        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  }
+  if (protection_flags[3] == 's') {
+    region->protection_flags |= base::trace_event::ProcessMemoryMaps::VMRegion::
+        kProtectionFlagsMayshare;
+  }
+
+  region->mapped_file = mapped_file;
+  base::TrimWhitespaceASCII(region->mapped_file, base::TRIM_ALL,
+                            &region->mapped_file);
+
+  return res;
+}
+
+uint64_t ReadCounterBytes(char* counter_line) {
+  uint64_t counter_value = 0;
+  int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value);
+  return res == 1 ? counter_value * 1024 : 0;
+}
+
+uint32_t ParseSmapsCounter(
+    char* counter_line,
+    base::trace_event::ProcessMemoryMaps::VMRegion* region) {
+  // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
+  uint32_t res = 1;
+  char counter_name[20];
+  int did_read = sscanf(counter_line, "%19[^\n ]", counter_name);
+  if (did_read != 1)
+    return 0;
+
+  if (strcmp(counter_name, "Pss:") == 0) {
+    region->byte_stats_proportional_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Private_Dirty:") == 0) {
+    region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Private_Clean:") == 0) {
+    region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Shared_Dirty:") == 0) {
+    region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Shared_Clean:") == 0) {
+    region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Swap:") == 0) {
+    region->byte_stats_swapped = ReadCounterBytes(counter_line);
+  } else {
+    res = 0;
+  }
+
+  return res;
+}
+
+uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file,
+                                base::trace_event::ProcessMemoryMaps* pmm) {
+  if (!smaps_file)
+    return 0;
+
+  fseek(smaps_file, 0, SEEK_SET);
+
+  char line[kMaxLineSize];
+  const uint32_t kNumExpectedCountersPerRegion = 6;
+  uint32_t counters_parsed_for_current_region = 0;
+  uint32_t num_valid_regions = 0;
+  base::trace_event::ProcessMemoryMaps::VMRegion region;
+  bool should_add_current_region = false;
+  for (;;) {
+    line[0] = '\0';
+    if (fgets(line, kMaxLineSize, smaps_file) == nullptr || !strlen(line))
+      break;
+    if (isxdigit(line[0]) && !isupper(line[0])) {
+      region = base::trace_event::ProcessMemoryMaps::VMRegion();
+      counters_parsed_for_current_region = 0;
+      should_add_current_region = ParseSmapsHeader(line, &region);
+    } else {
+      counters_parsed_for_current_region += ParseSmapsCounter(line, &region);
+      DCHECK_LE(counters_parsed_for_current_region,
+                kNumExpectedCountersPerRegion);
+      if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+        if (should_add_current_region) {
+          pmm->AddVMRegion(region);
+          ++num_valid_regions;
+          should_add_current_region = false;
+        }
+      }
+    }
+  }
+  return num_valid_regions;
+}
+
 }  // namespace
 
-void FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump) {
+FILE* g_proc_smaps_for_testing = nullptr;
+
+// static
+void OSMetrics::SetProcSmapsForTesting(FILE* f) {
+  g_proc_smaps_for_testing = f;
+}
+
+// static
+bool OSMetrics::FillOSMemoryDump(base::ProcessId pid,
+                                 mojom::RawOSMemDump* dump) {
   base::ScopedFD autoclose = OpenStatm(pid);
   int statm_fd = autoclose.get();
 
   if (statm_fd == -1)
-    return;
+    return false;
 
   uint64_t resident_pages;
   uint64_t shared_pages;
@@ -67,7 +195,7 @@
       statm_fd, &resident_pages, &shared_pages);
 
   if (!success)
-    return;
+    return false;
 
   auto process_metrics = CreateProcessMetrics(pid);
 
@@ -78,6 +206,32 @@
   dump->platform_private_footprint.rss_anon_bytes = rss_anon_bytes;
   dump->platform_private_footprint.vm_swap_bytes = vm_swap_bytes;
   dump->resident_set_kb = process_metrics->GetWorkingSetSize() / 1024;
+
+  return true;
+}
+
+// static
+bool OSMetrics::FillProcessMemoryMaps(
+    base::ProcessId pid,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  uint32_t res = 0;
+  if (g_proc_smaps_for_testing) {
+    res =
+        ReadLinuxProcSmapsFile(g_proc_smaps_for_testing, pmd->process_mmaps());
+  } else {
+    std::string file_name =
+        "/proc/" +
+        (pid == base::kNullProcessId ? "self" : base::IntToString(pid)) +
+        "/smaps";
+    base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r"));
+    res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps());
+  }
+
+  if (!res)
+    return false;
+
+  pmd->set_has_process_mmaps();
+  return true;
 }
 
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
index a418e861..8cb2e8b 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
@@ -4,11 +4,228 @@
 
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
+#include <libproc.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
+#include <sys/param.h>
+
+#include <mach-o/dyld_images.h>
+#include <mach-o/loader.h>
+#include <mach/mach.h>
+
+#include "base/numerics/safe_math.h"
 #include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
 
 namespace memory_instrumentation {
 
-void FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump) {
+namespace {
+
+using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+
+bool IsAddressInSharedRegion(uint64_t address) {
+  return address >= SHARED_REGION_BASE_X86_64 &&
+         address < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
+}
+
+bool IsRegionContainedInRegion(const VMRegion& containee,
+                               const VMRegion& container) {
+  uint64_t containee_end_address =
+      containee.start_address + containee.size_in_bytes;
+  uint64_t container_end_address =
+      container.start_address + container.size_in_bytes;
+  return containee.start_address >= container.start_address &&
+         containee_end_address <= container_end_address;
+}
+
+bool DoRegionsIntersect(const VMRegion& a, const VMRegion& b) {
+  uint64_t a_end_address = a.start_address + a.size_in_bytes;
+  uint64_t b_end_address = b.start_address + b.size_in_bytes;
+  return a.start_address < b_end_address && b.start_address < a_end_address;
+}
+
+// Creates VMRegions for all dyld images. Returns whether the operation
+// succeeded.
+bool GetDyldRegions(std::vector<VMRegion>* regions) {
+  task_dyld_info_data_t dyld_info;
+  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+  kern_return_t kr =
+      task_info(mach_task_self(), TASK_DYLD_INFO,
+                reinterpret_cast<task_info_t>(&dyld_info), &count);
+  if (kr != KERN_SUCCESS)
+    return false;
+
+  const struct dyld_all_image_infos* all_image_infos =
+      reinterpret_cast<const struct dyld_all_image_infos*>(
+          dyld_info.all_image_info_addr);
+
+  bool emitted_linkedit_from_dyld_shared_cache = false;
+  for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
+    const char* image_name = all_image_infos->infoArray[i].imageFilePath;
+
+    // The public definition for dyld_all_image_infos/dyld_image_info is wrong
+    // for 64-bit platforms. We explicitly cast to struct mach_header_64 even
+    // though the public definition claims that this is a struct mach_header.
+    const struct mach_header_64* const header =
+        reinterpret_cast<const struct mach_header_64* const>(
+            all_image_infos->infoArray[i].imageLoadAddress);
+
+    uint64_t next_command = reinterpret_cast<uint64_t>(header + 1);
+    uint64_t command_end = next_command + header->sizeofcmds;
+    uint64_t slide = 0;
+    for (unsigned int j = 0; j < header->ncmds; ++j) {
+      // Ensure that next_command doesn't run past header->sizeofcmds.
+      if (next_command + sizeof(struct load_command) > command_end)
+        return false;
+      const struct load_command* load_cmd =
+          reinterpret_cast<const struct load_command*>(next_command);
+      next_command += load_cmd->cmdsize;
+
+      if (load_cmd->cmd == LC_SEGMENT_64) {
+        if (load_cmd->cmdsize < sizeof(segment_command_64))
+          return false;
+        const segment_command_64* seg =
+            reinterpret_cast<const segment_command_64*>(load_cmd);
+        if (strcmp(seg->segname, SEG_PAGEZERO) == 0)
+          continue;
+        if (strcmp(seg->segname, SEG_TEXT) == 0) {
+          slide = reinterpret_cast<uint64_t>(header) - seg->vmaddr;
+        }
+
+        // Avoid emitting LINKEDIT regions in the dyld shared cache, since they
+        // all overlap.
+        if (IsAddressInSharedRegion(seg->vmaddr) &&
+            strcmp(seg->segname, SEG_LINKEDIT) == 0) {
+          if (emitted_linkedit_from_dyld_shared_cache) {
+            continue;
+          } else {
+            emitted_linkedit_from_dyld_shared_cache = true;
+            image_name = "dyld shared cache combined __LINKEDIT";
+          }
+        }
+
+        uint32_t protection_flags = 0;
+        if (seg->initprot & VM_PROT_READ)
+          protection_flags |= VMRegion::kProtectionFlagsRead;
+        if (seg->initprot & VM_PROT_WRITE)
+          protection_flags |= VMRegion::kProtectionFlagsWrite;
+        if (seg->initprot & VM_PROT_EXECUTE)
+          protection_flags |= VMRegion::kProtectionFlagsExec;
+
+        VMRegion region;
+        region.size_in_bytes = seg->vmsize;
+        region.protection_flags = protection_flags;
+        region.mapped_file = image_name;
+        region.start_address = slide + seg->vmaddr;
+
+        // We intentionally avoid setting any page information, which is not
+        // available from dyld. The fields will be populated later.
+        regions->push_back(region);
+      }
+    }
+  }
+  return true;
+}
+
+void PopulateByteStats(VMRegion* region,
+                       const vm_region_top_info_data_t& info) {
+  uint64_t dirty_bytes =
+      (info.private_pages_resident + info.shared_pages_resident) * PAGE_SIZE;
+  switch (info.share_mode) {
+    case SM_LARGE_PAGE:
+    case SM_PRIVATE:
+    case SM_COW:
+      region->byte_stats_private_dirty_resident = dirty_bytes;
+    case SM_SHARED:
+    case SM_PRIVATE_ALIASED:
+    case SM_TRUESHARED:
+    case SM_SHARED_ALIASED:
+      region->byte_stats_shared_dirty_resident = dirty_bytes;
+      break;
+    case SM_EMPTY:
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+// Creates VMRegions using mach vm syscalls. Returns whether the operation
+// succeeded.
+bool GetAllRegions(std::vector<VMRegion>* regions) {
+  const int pid = getpid();
+  task_t task = mach_task_self();
+  mach_vm_size_t size = 0;
+  mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
+  while (true) {
+    base::CheckedNumeric<mach_vm_address_t> next_address(address);
+    next_address += size;
+    if (!next_address.IsValid())
+      return false;
+    address = next_address.ValueOrDie();
+    mach_vm_address_t address_copy = address;
+
+    vm_region_top_info_data_t info;
+    base::MachVMRegionResult result =
+        base::GetTopInfo(task, &size, &address, &info);
+    if (result == base::MachVMRegionResult::Error)
+      return false;
+    if (result == base::MachVMRegionResult::Finished)
+      break;
+
+    vm_region_basic_info_64 basic_info;
+    mach_vm_size_t dummy_size = 0;
+    result = base::GetBasicInfo(task, &dummy_size, &address_copy, &basic_info);
+    if (result == base::MachVMRegionResult::Error)
+      return false;
+    if (result == base::MachVMRegionResult::Finished)
+      break;
+
+    VMRegion region;
+    PopulateByteStats(&region, info);
+
+    if (basic_info.protection & VM_PROT_READ)
+      region.protection_flags |= VMRegion::kProtectionFlagsRead;
+    if (basic_info.protection & VM_PROT_WRITE)
+      region.protection_flags |= VMRegion::kProtectionFlagsWrite;
+    if (basic_info.protection & VM_PROT_EXECUTE)
+      region.protection_flags |= VMRegion::kProtectionFlagsExec;
+
+    char buffer[MAXPATHLEN];
+    int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN);
+    if (length != 0)
+      region.mapped_file.assign(buffer, length);
+
+    // There's no way to get swapped or clean bytes without doing a
+    // very expensive syscalls that crawls every single page in the memory
+    // object.
+    region.start_address = address;
+    region.size_in_bytes = size;
+    regions->push_back(region);
+  }
+  return true;
+}
+
+void AddRegionByteStats(VMRegion* dest, const VMRegion& source) {
+  dest->byte_stats_private_dirty_resident +=
+      source.byte_stats_private_dirty_resident;
+  dest->byte_stats_private_clean_resident +=
+      source.byte_stats_private_clean_resident;
+  dest->byte_stats_shared_dirty_resident +=
+      source.byte_stats_shared_dirty_resident;
+  dest->byte_stats_shared_clean_resident +=
+      source.byte_stats_shared_clean_resident;
+  dest->byte_stats_swapped += source.byte_stats_swapped;
+  dest->byte_stats_proportional_resident +=
+      source.byte_stats_proportional_resident;
+}
+
+}  // namespace
+
+// static
+bool OSMetrics::FillOSMemoryDump(base::ProcessId pid,
+                                 mojom::RawOSMemDump* dump) {
   // Creating process metrics for child processes in mac or windows requires
   // additional information like ProcessHandle or port provider.
   DCHECK_EQ(base::kNullProcessId, pid);
@@ -20,13 +237,67 @@
   size_t locked_bytes;
   if (!process_metrics->GetMemoryBytes(&private_bytes, &shared_bytes,
                                        &resident_bytes, &locked_bytes)) {
-    return;
+    return false;
   }
   base::ProcessMetrics::TaskVMInfo info = process_metrics->GetTaskVMInfo();
   dump->platform_private_footprint.phys_footprint_bytes = info.phys_footprint;
   dump->platform_private_footprint.internal_bytes = info.internal;
   dump->platform_private_footprint.compressed_bytes = info.compressed;
   dump->resident_set_kb = resident_bytes / 1024;
+  return true;
+}
+
+// static
+bool OSMetrics::FillProcessMemoryMaps(
+    base::ProcessId pid,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+
+  std::vector<VMRegion> dyld_regions;
+  if (!GetDyldRegions(&dyld_regions))
+    return false;
+  std::vector<VMRegion> all_regions;
+  if (!GetAllRegions(&all_regions))
+    return false;
+
+  // Merge information from dyld regions and all regions.
+  for (const VMRegion& region : all_regions) {
+    bool skip = false;
+    const bool in_shared_region = IsAddressInSharedRegion(region.start_address);
+    for (VMRegion& dyld_region : dyld_regions) {
+      // If this region is fully contained in a dyld region, then add the bytes
+      // stats.
+      if (IsRegionContainedInRegion(region, dyld_region)) {
+        AddRegionByteStats(&dyld_region, region);
+        skip = true;
+        break;
+      }
+
+      // Check to see if the region is likely used for the dyld shared cache.
+      if (in_shared_region) {
+        // This region is likely used for the dyld shared cache. Don't record
+        // any byte stats since:
+        //   1. It's not possible to figure out which dyld regions the byte
+        //      stats correspond to.
+        //   2. The region is likely shared by non-Chrome processes, so there's
+        //      no point in charging the pages towards Chrome.
+        if (DoRegionsIntersect(region, dyld_region)) {
+          skip = true;
+          break;
+        }
+      }
+    }
+    if (skip)
+      continue;
+    pmd->process_mmaps()->AddVMRegion(region);
+  }
+
+  for (VMRegion& region : dyld_regions) {
+    pmd->process_mmaps()->AddVMRegion(region);
+  }
+
+  pmd->set_has_process_mmaps();
+  return true;
 }
 
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
index 61cabc4..d2be3aae0 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
@@ -3,22 +3,300 @@
 // found in the LICENSE file.
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
+#include "base/files/file_util.h"
 #include "base/process/process_handle.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_MACOSX)
+#include <libgen.h>
+#include <mach-o/dyld.h>
+#endif
+
+#if defined(OS_WIN)
+#include <base/strings/sys_string_conversions.h>
+#endif
+
 namespace memory_instrumentation {
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+    "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
+    "Size:                760 kB\n"
+    "Rss:                 296 kB\n"
+    "Pss:                 162 kB\n"
+    "Shared_Clean:        228 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:        68 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:            68 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  4 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    "ff000000-ff800000 -w-p 00001080 fc:01 0            /file/name with space\n"
+    "Size:                  0 kB\n"
+    "Rss:                 192 kB\n"
+    "Pss:                 128 kB\n"
+    "Shared_Clean:        120 kB\n"
+    "Shared_Dirty:          4 kB\n"
+    "Private_Clean:        60 kB\n"
+    "Private_Dirty:         8 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+    // An invalid region, with zero size and overlapping with the last one
+    // (See crbug.com/461237).
+    "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A invalid region with its range going backwards.
+    "00400000-00200000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A good anonymous region at the end.
+    "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+    "Size:                 48 kB\n"
+    "Rss:                  40 kB\n"
+    "Pss:                  32 kB\n"
+    "Shared_Clean:         16 kB\n"
+    "Shared_Dirty:         12 kB\n"
+    "Private_Clean:         8 kB\n"
+    "Private_Dirty:         4 kB\n"
+    "Referenced:           40 kB\n"
+    "Anonymous:            16 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd wr mr mw me ac sd\n";
+
+void CreateTempFileWithContents(const char* contents, base::ScopedFILE* file) {
+  base::FilePath temp_path;
+  FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path);
+  file->reset(temp_file);
+  ASSERT_TRUE(temp_file);
+
+  ASSERT_TRUE(
+      base::WriteFileDescriptor(fileno(temp_file), contents, strlen(contents)));
+}
+
+}  // namespace
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
 TEST(OSMetricsTest, GivesNonZeroResults) {
   base::ProcessId pid = base::kNullProcessId;
-  mojom::RawOSMemDumpPtr dump = GetOSMemoryDump(pid);
+  mojom::RawOSMemDump dump;
+  EXPECT_TRUE(OSMetrics::FillOSMemoryDump(pid, &dump));
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-  EXPECT_GT(dump->platform_private_footprint.rss_anon_bytes, 0u);
+  EXPECT_GT(dump.platform_private_footprint.rss_anon_bytes, 0u);
 #elif defined(OS_WIN)
-  EXPECT_GT(dump->platform_private_footprint.private_bytes, 0u);
+  EXPECT_GT(dump.platform_private_footprint.private_bytes, 0u);
 #elif defined(OS_MACOSX)
-  EXPECT_GT(dump->platform_private_footprint.internal_bytes, 0u);
+  EXPECT_GT(dump.platform_private_footprint.internal_bytes, 0u);
 #endif
 }
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(OSMetricsTest, ParseProcSmaps) {
+  const uint32_t kProtR =
+      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  const uint32_t kProtW =
+      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  const uint32_t kProtX =
+      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  const base::trace_event::MemoryDumpArgs dump_args = {
+      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+
+  // Emulate an empty /proc/self/smaps.
+  base::trace_event::ProcessMemoryDump pmd_invalid(nullptr /* session_state */,
+                                                   dump_args);
+  base::ScopedFILE empty_file(OpenFile(base::FilePath("/dev/null"), "r"));
+  ASSERT_TRUE(empty_file.get());
+  OSMetrics::SetProcSmapsForTesting(empty_file.get());
+  OSMetrics::FillProcessMemoryMaps(base::kNullProcessId, &pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Parse the 1st smaps file.
+  base::trace_event::ProcessMemoryDump pmd_1(nullptr /* session_state */,
+                                             dump_args);
+  base::ScopedFILE temp_file1;
+  CreateTempFileWithContents(kTestSmaps1, &temp_file1);
+  OSMetrics::SetProcSmapsForTesting(temp_file1.get());
+  OSMetrics::FillProcessMemoryMaps(base::kNullProcessId, &pmd_1);
+  ASSERT_TRUE(pmd_1.has_process_mmaps());
+  const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+  ASSERT_EQ(2UL, regions_1.size());
+
+  EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+  EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+  EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+  EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+  EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
+  EXPECT_EQ(228 * 1024UL, regions_1[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[0].byte_stats_swapped);
+
+  EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+  EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+  EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+  EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+  EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
+  EXPECT_EQ(120 * 1024UL, regions_1[1].byte_stats_shared_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[1].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(60 * 1024UL, regions_1[1].byte_stats_private_clean_resident);
+  EXPECT_EQ(8 * 1024UL, regions_1[1].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped);
+
+  // Parse the 2nd smaps file.
+  base::trace_event::ProcessMemoryDump pmd_2(nullptr /* session_state */,
+                                             dump_args);
+  base::ScopedFILE temp_file2;
+  CreateTempFileWithContents(kTestSmaps2, &temp_file2);
+  OSMetrics::SetProcSmapsForTesting(temp_file2.get());
+  OSMetrics::FillProcessMemoryMaps(base::kNullProcessId, &pmd_2);
+  ASSERT_TRUE(pmd_2.has_process_mmaps());
+  const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+  ASSERT_EQ(1UL, regions_2.size());
+  EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+  EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+  EXPECT_EQ(0U, regions_2[0].protection_flags);
+  EXPECT_EQ("", regions_2[0].mapped_file);
+  EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
+  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(12 * 1024UL, regions_2[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(8 * 1024UL, regions_2[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_WIN)
+void DummyFunction() {}
+
+TEST(OSMetricsTest, TestWinModuleReading) {
+  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+
+  base::trace_event::MemoryDumpArgs args;
+  base::trace_event::ProcessMemoryDump dump(nullptr, args);
+  ASSERT_TRUE(OSMetrics::FillProcessMemoryMaps(base::kNullProcessId, &dump));
+  ASSERT_TRUE(dump.has_process_mmaps());
+
+  wchar_t module_name[MAX_PATH];
+  DWORD result = GetModuleFileName(nullptr, module_name, MAX_PATH);
+  ASSERT_TRUE(result);
+  std::string executable_name = base::SysWideToNativeMB(module_name);
+
+  HMODULE module_containing_dummy = nullptr;
+  uintptr_t dummy_function_address =
+      reinterpret_cast<uintptr_t>(&DummyFunction);
+  result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                             reinterpret_cast<LPCWSTR>(dummy_function_address),
+                             &module_containing_dummy);
+  ASSERT_TRUE(result);
+  result = GetModuleFileName(nullptr, module_name, MAX_PATH);
+  ASSERT_TRUE(result);
+  std::string module_containing_dummy_name =
+      base::SysWideToNativeMB(module_name);
+
+  bool found_executable = false;
+  bool found_region_with_dummy = false;
+  for (const VMRegion& region : dump.process_mmaps()->vm_regions()) {
+    EXPECT_NE(0u, region.start_address);
+    EXPECT_NE(0u, region.size_in_bytes);
+
+    if (region.mapped_file.find(executable_name) != std::string::npos)
+      found_executable = true;
+
+    if (dummy_function_address >= region.start_address &&
+        dummy_function_address < region.start_address + region.size_in_bytes) {
+      found_region_with_dummy = true;
+      EXPECT_EQ(module_containing_dummy_name, region.mapped_file);
+    }
+  }
+  EXPECT_TRUE(found_executable);
+  EXPECT_TRUE(found_region_with_dummy);
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+TEST(OSMetricsTest, TestMachOReading) {
+  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+  base::trace_event::MemoryDumpArgs args;
+  base::trace_event::ProcessMemoryDump dump(nullptr, args);
+  ASSERT_TRUE(OSMetrics::FillProcessMemoryMaps(base::kNullProcessId, &dump));
+  ASSERT_TRUE(dump.has_process_mmaps());
+  uint32_t size = 100;
+  char full_path[size];
+  int result = _NSGetExecutablePath(full_path, &size);
+  ASSERT_EQ(0, result);
+  std::string name = basename(full_path);
+
+  uint64_t components_unittests_resident_pages = 0;
+  bool found_appkit = false;
+  for (const VMRegion& region : dump.process_mmaps()->vm_regions()) {
+    EXPECT_NE(0u, region.start_address);
+    EXPECT_NE(0u, region.size_in_bytes);
+
+    EXPECT_LT(region.size_in_bytes, 1ull << 32);
+    uint32_t required_protection_flags =
+        VMRegion::kProtectionFlagsRead | VMRegion::kProtectionFlagsExec;
+    if (region.mapped_file.find(name) != std::string::npos &&
+        region.protection_flags == required_protection_flags) {
+      components_unittests_resident_pages +=
+          region.byte_stats_private_dirty_resident +
+          region.byte_stats_shared_dirty_resident +
+          region.byte_stats_private_clean_resident +
+          region.byte_stats_shared_clean_resident;
+    }
+
+    if (region.mapped_file.find("AppKit") != std::string::npos) {
+      found_appkit = true;
+    }
+  }
+  EXPECT_GT(components_unittests_resident_pages, 0u);
+  EXPECT_TRUE(found_appkit);
+}
+#endif  // defined(OS_MACOSX)
+
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
index feef20d3f..147f21b 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_win.cc
@@ -4,11 +4,20 @@
 
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
+#include <psapi.h>
+#include <tchar.h>
+#include <windows.h>
+
+#include <base/strings/sys_string_conversions.h>
+#include <base/win/pe_image.h>
+#include <base/win/win_util.h>
 #include "base/process/process_metrics.h"
 
 namespace memory_instrumentation {
 
-void FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump) {
+// static
+bool OSMetrics::FillOSMemoryDump(base::ProcessId pid,
+                                 mojom::RawOSMemDump* dump) {
   // Creating process metrics for child processes in mac or windows requires
   // additional information like ProcessHandle or port provider.
   DCHECK_EQ(base::kNullProcessId, pid);
@@ -18,6 +27,43 @@
   process_metrics->GetMemoryBytes(&private_bytes, nullptr);
   dump->platform_private_footprint.private_bytes = private_bytes;
   dump->resident_set_kb = process_metrics->GetWorkingSetSize() / 1024;
+  return true;
+}
+
+// static
+bool OSMetrics::FillProcessMemoryMaps(
+    base::ProcessId pid,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  std::vector<HMODULE> modules;
+  if (!base::win::GetLoadedModulesSnapshot(::GetCurrentProcess(), &modules))
+    return false;
+
+  // Query the base address for each module, and attach it to the dump.
+  for (size_t i = 0; i < modules.size(); ++i) {
+    wchar_t module_name[MAX_PATH];
+    if (!::GetModuleFileName(modules[i], module_name, MAX_PATH))
+      continue;
+
+    MODULEINFO module_info;
+    if (!::GetModuleInformation(::GetCurrentProcess(), modules[i], &module_info,
+                                sizeof(MODULEINFO))) {
+      continue;
+    }
+    base::trace_event::ProcessMemoryMaps::VMRegion region;
+    region.size_in_bytes = module_info.SizeOfImage;
+    region.mapped_file = base::SysWideToNativeMB(module_name);
+    region.start_address = reinterpret_cast<uint64_t>(module_info.lpBaseOfDll);
+
+    // The PE header field |TimeDateStamp| is required to build the PE code
+    // identifier which is used as a key to query symbols servers.
+    base::win::PEImage pe_image(module_info.lpBaseOfDll);
+    region.module_timestamp = pe_image.GetNTHeaders()->FileHeader.TimeDateStamp;
+
+    pmd->process_mmaps()->AddVMRegion(region);
+  }
+  if (!pmd->process_mmaps()->vm_regions().empty())
+    pmd->set_has_process_mmaps();
+  return true;
 }
 
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider.cc
index f6c73328..f54d3b9 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider.cc
@@ -25,31 +25,6 @@
 #include "build/build_config.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 
-#if defined(OS_MACOSX)
-#include <libproc.h>
-#include <mach/mach.h>
-#include <mach/mach_vm.h>
-#include <mach/shared_region.h>
-#include <sys/param.h>
-
-#include <mach-o/dyld_images.h>
-#include <mach-o/loader.h>
-#include <mach/mach.h>
-
-#include "base/numerics/safe_math.h"
-#include "base/process/process_metrics.h"
-#endif  // defined(OS_MACOSX)
-
-#if defined(OS_WIN)
-#include <psapi.h>
-#include <tchar.h>
-#include <windows.h>
-
-#include <base/strings/sys_string_conversions.h>
-#include <base/win/pe_image.h>
-#include <base/win/win_util.h>
-#endif  // defined(OS_WIN)
-
 namespace memory_instrumentation {
 
 namespace {
@@ -60,128 +35,10 @@
     g_dump_providers_map = LAZY_INSTANCE_INITIALIZER;
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
+
 const char kClearPeakRssCommand[] = "5";
-
 const uint32_t kMaxLineSize = 4096;
 
-bool ParseSmapsHeader(const char* header_line,
-                      base::trace_event::ProcessMemoryMaps::VMRegion* region) {
-  // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234  /foo.so\n"
-  bool res = true;  // Whether this region should be appended or skipped.
-  uint64_t end_addr = 0;
-  char protection_flags[5] = {0};
-  char mapped_file[kMaxLineSize];
-
-  if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n",
-             &region->start_address, &end_addr, protection_flags,
-             mapped_file) != 4)
-    return false;
-
-  if (end_addr > region->start_address) {
-    region->size_in_bytes = end_addr - region->start_address;
-  } else {
-    // This is not just paranoia, it can actually happen (See crbug.com/461237).
-    region->size_in_bytes = 0;
-    res = false;
-  }
-
-  region->protection_flags = 0;
-  if (protection_flags[0] == 'r') {
-    region->protection_flags |=
-        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
-  }
-  if (protection_flags[1] == 'w') {
-    region->protection_flags |=
-        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
-  }
-  if (protection_flags[2] == 'x') {
-    region->protection_flags |=
-        base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
-  }
-  if (protection_flags[3] == 's') {
-    region->protection_flags |= base::trace_event::ProcessMemoryMaps::VMRegion::
-        kProtectionFlagsMayshare;
-  }
-
-  region->mapped_file = mapped_file;
-  base::TrimWhitespaceASCII(region->mapped_file, base::TRIM_ALL,
-                            &region->mapped_file);
-
-  return res;
-}
-
-uint64_t ReadCounterBytes(char* counter_line) {
-  uint64_t counter_value = 0;
-  int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value);
-  return res == 1 ? counter_value * 1024 : 0;
-}
-
-uint32_t ParseSmapsCounter(
-    char* counter_line,
-    base::trace_event::ProcessMemoryMaps::VMRegion* region) {
-  // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
-  uint32_t res = 1;
-  char counter_name[20];
-  int did_read = sscanf(counter_line, "%19[^\n ]", counter_name);
-  if (did_read != 1)
-    return 0;
-
-  if (strcmp(counter_name, "Pss:") == 0) {
-    region->byte_stats_proportional_resident = ReadCounterBytes(counter_line);
-  } else if (strcmp(counter_name, "Private_Dirty:") == 0) {
-    region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line);
-  } else if (strcmp(counter_name, "Private_Clean:") == 0) {
-    region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line);
-  } else if (strcmp(counter_name, "Shared_Dirty:") == 0) {
-    region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line);
-  } else if (strcmp(counter_name, "Shared_Clean:") == 0) {
-    region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
-  } else if (strcmp(counter_name, "Swap:") == 0) {
-    region->byte_stats_swapped = ReadCounterBytes(counter_line);
-  } else {
-    res = 0;
-  }
-
-  return res;
-}
-
-uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file,
-                                base::trace_event::ProcessMemoryMaps* pmm) {
-  if (!smaps_file)
-    return 0;
-
-  fseek(smaps_file, 0, SEEK_SET);
-
-  char line[kMaxLineSize];
-  const uint32_t kNumExpectedCountersPerRegion = 6;
-  uint32_t counters_parsed_for_current_region = 0;
-  uint32_t num_valid_regions = 0;
-  base::trace_event::ProcessMemoryMaps::VMRegion region;
-  bool should_add_current_region = false;
-  for (;;) {
-    line[0] = '\0';
-    if (fgets(line, kMaxLineSize, smaps_file) == nullptr || !strlen(line))
-      break;
-    if (isxdigit(line[0]) && !isupper(line[0])) {
-      region = base::trace_event::ProcessMemoryMaps::VMRegion();
-      counters_parsed_for_current_region = 0;
-      should_add_current_region = ParseSmapsHeader(line, &region);
-    } else {
-      counters_parsed_for_current_region += ParseSmapsCounter(line, &region);
-      DCHECK_LE(counters_parsed_for_current_region,
-                kNumExpectedCountersPerRegion);
-      if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
-        if (should_add_current_region) {
-          pmm->AddVMRegion(region);
-          ++num_valid_regions;
-          should_add_current_region = false;
-        }
-      }
-    }
-  }
-  return num_valid_regions;
-}
-
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
@@ -209,343 +66,6 @@
 ProcessMetricsMemoryDumpProvider::FactoryFunction
     ProcessMetricsMemoryDumpProvider::factory_for_testing = nullptr;
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-
-// static
-FILE* ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = nullptr;
-
-// static
-int ProcessMetricsMemoryDumpProvider::fast_polling_statm_fd_for_testing = -1;
-
-bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  uint32_t res = 0;
-  if (proc_smaps_for_testing) {
-    res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
-  } else {
-    std::string file_name =
-        "/proc/" +
-        (process_ == base::kNullProcessId ? "self"
-                                          : base::IntToString(process_)) +
-        "/smaps";
-    base::ScopedFILE smaps_file(fopen(file_name.c_str(), "r"));
-    res = ReadLinuxProcSmapsFile(smaps_file.get(), pmd->process_mmaps());
-  }
-
-  if (res)
-    pmd->set_has_process_mmaps();
-  return res;
-}
-
-bool GetResidentPagesFromStatmFile(int fd, uint64_t* resident_pages) {
-  lseek(fd, 0, SEEK_SET);
-  char line[kMaxLineSize];
-  int res = read(fd, line, kMaxLineSize - 1);
-  if (res <= 0)
-    return false;
-  line[res] = '\0';
-  int num_scanned = sscanf(line, "%*s %" SCNu64, resident_pages);
-  return num_scanned == 1;
-}
-
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
-
-#if defined(OS_WIN)
-bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  std::vector<HMODULE> modules;
-  if (!base::win::GetLoadedModulesSnapshot(::GetCurrentProcess(), &modules))
-    return false;
-
-  // Query the base address for each module, and attach it to the dump.
-  for (size_t i = 0; i < modules.size(); ++i) {
-    wchar_t module_name[MAX_PATH];
-    if (!::GetModuleFileName(modules[i], module_name, MAX_PATH))
-      continue;
-
-    MODULEINFO module_info;
-    if (!::GetModuleInformation(::GetCurrentProcess(), modules[i], &module_info,
-                                sizeof(MODULEINFO))) {
-      continue;
-    }
-    base::trace_event::ProcessMemoryMaps::VMRegion region;
-    region.size_in_bytes = module_info.SizeOfImage;
-    region.mapped_file = base::SysWideToNativeMB(module_name);
-    region.start_address = reinterpret_cast<uint64_t>(module_info.lpBaseOfDll);
-
-    // The PE header field |TimeDateStamp| is required to build the PE code
-    // identifier which is used as a key to query symbols servers.
-    base::win::PEImage pe_image(module_info.lpBaseOfDll);
-    region.module_timestamp = pe_image.GetNTHeaders()->FileHeader.TimeDateStamp;
-
-    pmd->process_mmaps()->AddVMRegion(region);
-  }
-  if (!pmd->process_mmaps()->vm_regions().empty())
-    pmd->set_has_process_mmaps();
-  return true;
-}
-#endif  // defined(OS_WIN)
-
-#if defined(OS_MACOSX)
-
-namespace {
-
-using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
-
-bool IsAddressInSharedRegion(uint64_t address) {
-  return address >= SHARED_REGION_BASE_X86_64 &&
-         address < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
-}
-
-bool IsRegionContainedInRegion(const VMRegion& containee,
-                               const VMRegion& container) {
-  uint64_t containee_end_address =
-      containee.start_address + containee.size_in_bytes;
-  uint64_t container_end_address =
-      container.start_address + container.size_in_bytes;
-  return containee.start_address >= container.start_address &&
-         containee_end_address <= container_end_address;
-}
-
-bool DoRegionsIntersect(const VMRegion& a, const VMRegion& b) {
-  uint64_t a_end_address = a.start_address + a.size_in_bytes;
-  uint64_t b_end_address = b.start_address + b.size_in_bytes;
-  return a.start_address < b_end_address && b.start_address < a_end_address;
-}
-
-// Creates VMRegions for all dyld images. Returns whether the operation
-// succeeded.
-bool GetDyldRegions(std::vector<VMRegion>* regions) {
-  task_dyld_info_data_t dyld_info;
-  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
-  kern_return_t kr =
-      task_info(mach_task_self(), TASK_DYLD_INFO,
-                reinterpret_cast<task_info_t>(&dyld_info), &count);
-  if (kr != KERN_SUCCESS)
-    return false;
-
-  const struct dyld_all_image_infos* all_image_infos =
-      reinterpret_cast<const struct dyld_all_image_infos*>(
-          dyld_info.all_image_info_addr);
-
-  bool emitted_linkedit_from_dyld_shared_cache = false;
-  for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
-    const char* image_name = all_image_infos->infoArray[i].imageFilePath;
-
-    // The public definition for dyld_all_image_infos/dyld_image_info is wrong
-    // for 64-bit platforms. We explicitly cast to struct mach_header_64 even
-    // though the public definition claims that this is a struct mach_header.
-    const struct mach_header_64* const header =
-        reinterpret_cast<const struct mach_header_64* const>(
-            all_image_infos->infoArray[i].imageLoadAddress);
-
-    uint64_t next_command = reinterpret_cast<uint64_t>(header + 1);
-    uint64_t command_end = next_command + header->sizeofcmds;
-    uint64_t slide = 0;
-    for (unsigned int j = 0; j < header->ncmds; ++j) {
-      // Ensure that next_command doesn't run past header->sizeofcmds.
-      if (next_command + sizeof(struct load_command) > command_end)
-        return false;
-      const struct load_command* load_cmd =
-          reinterpret_cast<const struct load_command*>(next_command);
-      next_command += load_cmd->cmdsize;
-
-      if (load_cmd->cmd == LC_SEGMENT_64) {
-        if (load_cmd->cmdsize < sizeof(segment_command_64))
-          return false;
-        const segment_command_64* seg =
-            reinterpret_cast<const segment_command_64*>(load_cmd);
-        if (strcmp(seg->segname, SEG_PAGEZERO) == 0)
-          continue;
-        if (strcmp(seg->segname, SEG_TEXT) == 0) {
-          slide = reinterpret_cast<uint64_t>(header) - seg->vmaddr;
-        }
-
-        // Avoid emitting LINKEDIT regions in the dyld shared cache, since they
-        // all overlap.
-        if (IsAddressInSharedRegion(seg->vmaddr) &&
-            strcmp(seg->segname, SEG_LINKEDIT) == 0) {
-          if (emitted_linkedit_from_dyld_shared_cache) {
-            continue;
-          } else {
-            emitted_linkedit_from_dyld_shared_cache = true;
-            image_name = "dyld shared cache combined __LINKEDIT";
-          }
-        }
-
-        uint32_t protection_flags = 0;
-        if (seg->initprot & VM_PROT_READ)
-          protection_flags |= VMRegion::kProtectionFlagsRead;
-        if (seg->initprot & VM_PROT_WRITE)
-          protection_flags |= VMRegion::kProtectionFlagsWrite;
-        if (seg->initprot & VM_PROT_EXECUTE)
-          protection_flags |= VMRegion::kProtectionFlagsExec;
-
-        VMRegion region;
-        region.size_in_bytes = seg->vmsize;
-        region.protection_flags = protection_flags;
-        region.mapped_file = image_name;
-        region.start_address = slide + seg->vmaddr;
-
-        // We intentionally avoid setting any page information, which is not
-        // available from dyld. The fields will be populated later.
-        regions->push_back(region);
-      }
-    }
-  }
-  return true;
-}
-
-void PopulateByteStats(VMRegion* region,
-                       const vm_region_top_info_data_t& info) {
-  uint64_t dirty_bytes =
-      (info.private_pages_resident + info.shared_pages_resident) * PAGE_SIZE;
-  switch (info.share_mode) {
-    case SM_LARGE_PAGE:
-    case SM_PRIVATE:
-    case SM_COW:
-      region->byte_stats_private_dirty_resident = dirty_bytes;
-    case SM_SHARED:
-    case SM_PRIVATE_ALIASED:
-    case SM_TRUESHARED:
-    case SM_SHARED_ALIASED:
-      region->byte_stats_shared_dirty_resident = dirty_bytes;
-      break;
-    case SM_EMPTY:
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-// Creates VMRegions using mach vm syscalls. Returns whether the operation
-// succeeded.
-bool GetAllRegions(std::vector<VMRegion>* regions) {
-  const int pid = getpid();
-  task_t task = mach_task_self();
-  mach_vm_size_t size = 0;
-  mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
-  while (true) {
-    base::CheckedNumeric<mach_vm_address_t> next_address(address);
-    next_address += size;
-    if (!next_address.IsValid())
-      return false;
-    address = next_address.ValueOrDie();
-    mach_vm_address_t address_copy = address;
-
-    vm_region_top_info_data_t info;
-    base::MachVMRegionResult result =
-        base::GetTopInfo(task, &size, &address, &info);
-    if (result == base::MachVMRegionResult::Error)
-      return false;
-    if (result == base::MachVMRegionResult::Finished)
-      break;
-
-    vm_region_basic_info_64 basic_info;
-    mach_vm_size_t dummy_size = 0;
-    result = base::GetBasicInfo(task, &dummy_size, &address_copy, &basic_info);
-    if (result == base::MachVMRegionResult::Error)
-      return false;
-    if (result == base::MachVMRegionResult::Finished)
-      break;
-
-    VMRegion region;
-    PopulateByteStats(&region, info);
-
-    if (basic_info.protection & VM_PROT_READ)
-      region.protection_flags |= VMRegion::kProtectionFlagsRead;
-    if (basic_info.protection & VM_PROT_WRITE)
-      region.protection_flags |= VMRegion::kProtectionFlagsWrite;
-    if (basic_info.protection & VM_PROT_EXECUTE)
-      region.protection_flags |= VMRegion::kProtectionFlagsExec;
-
-    char buffer[MAXPATHLEN];
-    int length = proc_regionfilename(pid, address, buffer, MAXPATHLEN);
-    if (length != 0)
-      region.mapped_file.assign(buffer, length);
-
-    // There's no way to get swapped or clean bytes without doing a
-    // very expensive syscalls that crawls every single page in the memory
-    // object.
-    region.start_address = address;
-    region.size_in_bytes = size;
-    regions->push_back(region);
-  }
-  return true;
-}
-
-void AddRegionByteStats(VMRegion* dest, const VMRegion& source) {
-  dest->byte_stats_private_dirty_resident +=
-      source.byte_stats_private_dirty_resident;
-  dest->byte_stats_private_clean_resident +=
-      source.byte_stats_private_clean_resident;
-  dest->byte_stats_shared_dirty_resident +=
-      source.byte_stats_shared_dirty_resident;
-  dest->byte_stats_shared_clean_resident +=
-      source.byte_stats_shared_clean_resident;
-  dest->byte_stats_swapped += source.byte_stats_swapped;
-  dest->byte_stats_proportional_resident +=
-      source.byte_stats_proportional_resident;
-}
-
-}  // namespace
-
-bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
-
-  std::vector<VMRegion> dyld_regions;
-  if (!GetDyldRegions(&dyld_regions))
-    return false;
-  std::vector<VMRegion> all_regions;
-  if (!GetAllRegions(&all_regions))
-    return false;
-
-  // Merge information from dyld regions and all regions.
-  for (const VMRegion& region : all_regions) {
-    bool skip = false;
-    const bool in_shared_region = IsAddressInSharedRegion(region.start_address);
-    for (VMRegion& dyld_region : dyld_regions) {
-      // If this region is fully contained in a dyld region, then add the bytes
-      // stats.
-      if (IsRegionContainedInRegion(region, dyld_region)) {
-        AddRegionByteStats(&dyld_region, region);
-        skip = true;
-        break;
-      }
-
-      // Check to see if the region is likely used for the dyld shared cache.
-      if (in_shared_region) {
-        // This region is likely used for the dyld shared cache. Don't record
-        // any byte stats since:
-        //   1. It's not possible to figure out which dyld regions the byte
-        //      stats correspond to.
-        //   2. The region is likely shared by non-Chrome processes, so there's
-        //      no point in charging the pages towards Chrome.
-        if (DoRegionsIntersect(region, dyld_region)) {
-          skip = true;
-          break;
-        }
-      }
-    }
-    if (skip)
-      continue;
-    pmd->process_mmaps()->AddVMRegion(region);
-  }
-
-  for (VMRegion& region : dyld_regions) {
-    pmd->process_mmaps()->AddVMRegion(region);
-  }
-
-  pmd->set_has_process_mmaps();
-  return true;
-}
-#endif  // defined(OS_MACOSX)
-
 // static
 void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
     base::ProcessId process) {
@@ -608,6 +128,12 @@
   return res;
 }
 
+bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  return OSMetrics::FillProcessMemoryMaps(process_, pmd);
+}
+
 bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* pmd) {
@@ -641,9 +167,12 @@
   pmd->process_totals()->SetExtraFieldInBytes("locked_bytes", locked_bytes);
 #endif  // defined(OS_MACOSX)
 
-  mojom::RawOSMemDumpPtr dump = GetOSMemoryDump(process_);
+  mojom::RawOSMemDump dump;
+  if (!OSMetrics::FillOSMemoryDump(process_, &dump)) {
+    return false;
+  }
 
-  uint64_t rss_bytes = dump->resident_set_kb * 1024;
+  uint64_t rss_bytes = dump.resident_set_kb * 1024;
   if (rss_bytes_for_testing) {
     rss_bytes = rss_bytes_for_testing;
   }
@@ -655,7 +184,7 @@
 
   pmd->process_totals()->set_resident_set_bytes(rss_bytes);
   pmd->process_totals()->SetPlatformPrivateFootprint(
-      dump->platform_private_footprint);
+      dump.platform_private_footprint);
   pmd->set_has_process_totals();
   pmd->process_totals()->set_peak_resident_set_bytes(GetPeakResidentSetBytes());
 
@@ -692,6 +221,10 @@
 }
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+int ProcessMetricsMemoryDumpProvider::fast_polling_statm_fd_for_testing = -1;
+
 base::ScopedFD ProcessMetricsMemoryDumpProvider::OpenStatm() {
   std::string name =
       "/proc/" +
@@ -702,6 +235,18 @@
   DCHECK(fd.is_valid());
   return fd;
 }
+
+bool GetResidentPagesFromStatmFile(int fd, uint64_t* resident_pages) {
+  lseek(fd, 0, SEEK_SET);
+  char line[kMaxLineSize];
+  int res = read(fd, line, kMaxLineSize - 1);
+  if (res <= 0)
+    return false;
+  line[res] = '\0';
+  int num_scanned = sscanf(line, "%*s %" SCNu64, resident_pages);
+  return num_scanned == 1;
+}
+
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 void ProcessMetricsMemoryDumpProvider::PollFastMemoryTotal(
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider_unittest.cc
index b997757..1981395b 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider_unittest.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/process_metrics_memory_dump_provider_unittest.cc
@@ -17,110 +17,14 @@
 #include "base/trace_event/process_memory_maps.h"
 #include "base/trace_event/process_memory_totals.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
 #include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_MACOSX)
-#include <libgen.h>
-#include <mach-o/dyld.h>
-#endif
-
-#if defined(OS_WIN)
-#include <base/strings/sys_string_conversions.h>
-#endif
-
 namespace memory_instrumentation {
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 namespace {
-const char kTestSmaps1[] =
-    "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
-    "Size:                760 kB\n"
-    "Rss:                 296 kB\n"
-    "Pss:                 162 kB\n"
-    "Shared_Clean:        228 kB\n"
-    "Shared_Dirty:          0 kB\n"
-    "Private_Clean:         0 kB\n"
-    "Private_Dirty:        68 kB\n"
-    "Referenced:          296 kB\n"
-    "Anonymous:            68 kB\n"
-    "AnonHugePages:         0 kB\n"
-    "Swap:                  4 kB\n"
-    "KernelPageSize:        4 kB\n"
-    "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
-    "VmFlags: rd ex mr mw me dw sd\n"
-    "ff000000-ff800000 -w-p 00001080 fc:01 0            /file/name with space\n"
-    "Size:                  0 kB\n"
-    "Rss:                 192 kB\n"
-    "Pss:                 128 kB\n"
-    "Shared_Clean:        120 kB\n"
-    "Shared_Dirty:          4 kB\n"
-    "Private_Clean:        60 kB\n"
-    "Private_Dirty:         8 kB\n"
-    "Referenced:          296 kB\n"
-    "Anonymous:             0 kB\n"
-    "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
-    "KernelPageSize:        4 kB\n"
-    "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
-    "VmFlags: rd ex mr mw me dw sd";
-
-const char kTestSmaps2[] =
-    // An invalid region, with zero size and overlapping with the last one
-    // (See crbug.com/461237).
-    "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
-    "Size:                  4 kB\n"
-    "Rss:                   0 kB\n"
-    "Pss:                   0 kB\n"
-    "Shared_Clean:          0 kB\n"
-    "Shared_Dirty:          0 kB\n"
-    "Private_Clean:         0 kB\n"
-    "Private_Dirty:         0 kB\n"
-    "Referenced:            0 kB\n"
-    "Anonymous:             0 kB\n"
-    "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
-    "KernelPageSize:        4 kB\n"
-    "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
-    "VmFlags: rd ex mr mw me dw sd\n"
-    // A invalid region with its range going backwards.
-    "00400000-00200000 ---p 00000000 00:00 0 \n"
-    "Size:                  4 kB\n"
-    "Rss:                   0 kB\n"
-    "Pss:                   0 kB\n"
-    "Shared_Clean:          0 kB\n"
-    "Shared_Dirty:          0 kB\n"
-    "Private_Clean:         0 kB\n"
-    "Private_Dirty:         0 kB\n"
-    "Referenced:            0 kB\n"
-    "Anonymous:             0 kB\n"
-    "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
-    "KernelPageSize:        4 kB\n"
-    "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
-    "VmFlags: rd ex mr mw me dw sd\n"
-    // A good anonymous region at the end.
-    "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
-    "Size:                 48 kB\n"
-    "Rss:                  40 kB\n"
-    "Pss:                  32 kB\n"
-    "Shared_Clean:         16 kB\n"
-    "Shared_Dirty:         12 kB\n"
-    "Private_Clean:         8 kB\n"
-    "Private_Dirty:         4 kB\n"
-    "Referenced:           40 kB\n"
-    "Anonymous:            16 kB\n"
-    "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
-    "KernelPageSize:        4 kB\n"
-    "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
-    "VmFlags: rd wr mr mw me ac sd\n";
-
 const char kTestStatm[] = "200 100 20 2 3 4";
 
 void CreateTempFileWithContents(const char* contents, base::ScopedFILE* file) {
@@ -156,23 +60,23 @@
 }
 
 TEST(ProcessMetricsMemoryDumpProviderTest, DumpRSS) {
-  const base::trace_event::MemoryDumpArgs high_detail_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  const base::trace_event::MemoryDumpArgs args = {
+      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND};
   std::unique_ptr<ProcessMetricsMemoryDumpProvider> pmtdp(
       new ProcessMetricsMemoryDumpProvider(base::kNullProcessId));
   std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd_before(
-      new base::trace_event::ProcessMemoryDump(nullptr, high_detail_args));
+      new base::trace_event::ProcessMemoryDump(nullptr, args));
   std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd_after(
-      new base::trace_event::ProcessMemoryDump(nullptr, high_detail_args));
+      new base::trace_event::ProcessMemoryDump(nullptr, args));
 
   ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 1024;
-  pmtdp->OnMemoryDump(high_detail_args, pmd_before.get());
+  pmtdp->OnMemoryDump(args, pmd_before.get());
 
   // Pretend that the RSS of the process increased of +1M.
   const size_t kAllocSize = 1048576;
   ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing += kAllocSize;
 
-  pmtdp->OnMemoryDump(high_detail_args, pmd_after.get());
+  pmtdp->OnMemoryDump(args, pmd_after.get());
 
   ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0;
 
@@ -190,82 +94,6 @@
 }
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-TEST(ProcessMetricsMemoryDumpProviderTest, ParseProcSmaps) {
-  const uint32_t kProtR =
-      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
-  const uint32_t kProtW =
-      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
-  const uint32_t kProtX =
-      base::trace_event::ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
-  const base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
-
-  std::unique_ptr<ProcessMetricsMemoryDumpProvider> pmmdp(
-      new ProcessMetricsMemoryDumpProvider(base::kNullProcessId));
-
-  // Emulate an empty /proc/self/smaps.
-  base::trace_event::ProcessMemoryDump pmd_invalid(nullptr /* session_state */,
-                                                   dump_args);
-  base::ScopedFILE empty_file(OpenFile(base::FilePath("/dev/null"), "r"));
-  ASSERT_TRUE(empty_file.get());
-  ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = empty_file.get();
-  pmmdp->OnMemoryDump(dump_args, &pmd_invalid);
-  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
-
-  // Parse the 1st smaps file.
-  base::trace_event::ProcessMemoryDump pmd_1(nullptr /* session_state */,
-                                             dump_args);
-  base::ScopedFILE temp_file1;
-  CreateTempFileWithContents(kTestSmaps1, &temp_file1);
-  ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file1.get();
-  pmmdp->OnMemoryDump(dump_args, &pmd_1);
-  ASSERT_TRUE(pmd_1.has_process_mmaps());
-  const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
-  ASSERT_EQ(2UL, regions_1.size());
-
-  EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
-  EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
-  EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
-  EXPECT_EQ("/file/1", regions_1[0].mapped_file);
-  EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
-  EXPECT_EQ(228 * 1024UL, regions_1[0].byte_stats_shared_clean_resident);
-  EXPECT_EQ(0UL, regions_1[0].byte_stats_shared_dirty_resident);
-  EXPECT_EQ(0UL, regions_1[0].byte_stats_private_clean_resident);
-  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_private_dirty_resident);
-  EXPECT_EQ(4 * 1024UL, regions_1[0].byte_stats_swapped);
-
-  EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
-  EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
-  EXPECT_EQ(kProtW, regions_1[1].protection_flags);
-  EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
-  EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
-  EXPECT_EQ(120 * 1024UL, regions_1[1].byte_stats_shared_clean_resident);
-  EXPECT_EQ(4 * 1024UL, regions_1[1].byte_stats_shared_dirty_resident);
-  EXPECT_EQ(60 * 1024UL, regions_1[1].byte_stats_private_clean_resident);
-  EXPECT_EQ(8 * 1024UL, regions_1[1].byte_stats_private_dirty_resident);
-  EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped);
-
-  // Parse the 2nd smaps file.
-  base::trace_event::ProcessMemoryDump pmd_2(nullptr /* session_state */,
-                                             dump_args);
-  base::ScopedFILE temp_file2;
-  CreateTempFileWithContents(kTestSmaps2, &temp_file2);
-  ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file2.get();
-  pmmdp->OnMemoryDump(dump_args, &pmd_2);
-  ASSERT_TRUE(pmd_2.has_process_mmaps());
-  const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
-  ASSERT_EQ(1UL, regions_2.size());
-  EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
-  EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
-  EXPECT_EQ(0U, regions_2[0].protection_flags);
-  EXPECT_EQ("", regions_2[0].mapped_file);
-  EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
-  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_shared_clean_resident);
-  EXPECT_EQ(12 * 1024UL, regions_2[0].byte_stats_shared_dirty_resident);
-  EXPECT_EQ(8 * 1024UL, regions_2[0].byte_stats_private_clean_resident);
-  EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
-  EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
-}
 
 TEST(ProcessMetricsMemoryDumpProviderTest, DoubleRegister) {
   auto factory = [](base::ProcessId process) {
@@ -321,96 +149,4 @@
 #endif
 }
 
-#if defined(OS_WIN)
-
-void DummyFunction() {}
-
-TEST(ProcessMetricsMemoryDumpProviderTest, TestWinModuleReading) {
-  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
-
-  ProcessMetricsMemoryDumpProvider mdp(base::kNullProcessId);
-  base::trace_event::MemoryDumpArgs args;
-  base::trace_event::ProcessMemoryDump dump(nullptr, args);
-  ASSERT_TRUE(mdp.DumpProcessMemoryMaps(args, &dump));
-  ASSERT_TRUE(dump.has_process_mmaps());
-
-  wchar_t module_name[MAX_PATH];
-  DWORD result = GetModuleFileName(nullptr, module_name, MAX_PATH);
-  ASSERT_TRUE(result);
-  std::string executable_name = base::SysWideToNativeMB(module_name);
-
-  HMODULE module_containing_dummy = nullptr;
-  uintptr_t dummy_function_address =
-      reinterpret_cast<uintptr_t>(&DummyFunction);
-  result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                             reinterpret_cast<LPCWSTR>(dummy_function_address),
-                             &module_containing_dummy);
-  ASSERT_TRUE(result);
-  result = GetModuleFileName(nullptr, module_name, MAX_PATH);
-  ASSERT_TRUE(result);
-  std::string module_containing_dummy_name =
-      base::SysWideToNativeMB(module_name);
-
-  bool found_executable = false;
-  bool found_region_with_dummy = false;
-  for (const VMRegion& region : dump.process_mmaps()->vm_regions()) {
-    EXPECT_NE(0u, region.start_address);
-    EXPECT_NE(0u, region.size_in_bytes);
-
-    if (region.mapped_file.find(executable_name) != std::string::npos)
-      found_executable = true;
-
-    if (dummy_function_address >= region.start_address &&
-        dummy_function_address < region.start_address + region.size_in_bytes) {
-      found_region_with_dummy = true;
-      EXPECT_EQ(module_containing_dummy_name, region.mapped_file);
-    }
-  }
-  EXPECT_TRUE(found_executable);
-  EXPECT_TRUE(found_region_with_dummy);
-}
-#endif
-
-#if defined(OS_MACOSX)
-TEST(ProcessMetricsMemoryDumpProviderTest, TestMachOReading) {
-  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
-  ProcessMetricsMemoryDumpProvider mdp(base::kNullProcessId);
-  base::trace_event::MemoryDumpArgs args;
-  base::trace_event::ProcessMemoryDump dump(nullptr, args);
-  ASSERT_TRUE(mdp.DumpProcessMemoryMaps(args, &dump));
-  ASSERT_TRUE(dump.has_process_mmaps());
-  uint32_t size = 100;
-  char full_path[size];
-  int result = _NSGetExecutablePath(full_path, &size);
-  ASSERT_EQ(0, result);
-  std::string name = basename(full_path);
-
-  uint64_t components_unittests_resident_pages = 0;
-  bool found_appkit = false;
-  for (const VMRegion& region : dump.process_mmaps()->vm_regions()) {
-    EXPECT_NE(0u, region.start_address);
-    EXPECT_NE(0u, region.size_in_bytes);
-
-    EXPECT_LT(region.size_in_bytes, 1ull << 32);
-    uint32_t required_protection_flags =
-        VMRegion::kProtectionFlagsRead | VMRegion::kProtectionFlagsExec;
-    if (region.mapped_file.find(name) != std::string::npos &&
-        region.protection_flags == required_protection_flags) {
-      components_unittests_resident_pages +=
-          region.byte_stats_private_dirty_resident +
-          region.byte_stats_shared_dirty_resident +
-          region.byte_stats_private_clean_resident +
-          region.byte_stats_shared_clean_resident;
-    }
-
-    if (region.mapped_file.find("AppKit") != std::string::npos) {
-      found_appkit = true;
-    }
-  }
-  EXPECT_GT(components_unittests_resident_pages, 0u);
-  EXPECT_TRUE(found_appkit);
-}
-
-#endif  // defined(OS_MACOSX)
-
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
new file mode 100644
index 0000000..d960574
--- /dev/null
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
@@ -0,0 +1,702 @@
+// 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/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_manager_test_utils.h"
+#include "base/trace_event/memory_dump_scheduler.h"
+#include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
+#include "base/trace_event/trace_log.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
+#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::trace_event::MemoryAllocatorDump;
+using base::trace_event::MemoryDumpArgs;
+using base::trace_event::MemoryDumpCallbackResult;
+using base::trace_event::MemoryDumpLevelOfDetail;
+using base::trace_event::MemoryDumpManager;
+using base::trace_event::MemoryDumpProvider;
+using base::trace_event::MemoryDumpRequestArgs;
+using base::trace_event::MemoryDumpScheduler;
+using base::trace_event::MemoryDumpType;
+using base::trace_event::ProcessMemoryDump;
+using base::trace_event::TraceConfig;
+using base::trace_event::TraceLog;
+using base::trace_event::TraceResultBuffer;
+using testing::_;
+using testing::AnyNumber;
+using testing::Invoke;
+using testing::Return;
+
+namespace memory_instrumentation {
+
+namespace {
+
+const char kMDPName[] = "TestDumpProvider";
+const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
+const char* kBackgroundButNotSummaryWhitelistedMDPName =
+    "BackgroundButNotSummaryWhitelistedTestDumpProvider";
+const char* const kTestMDPWhitelist[] = {
+    kWhitelistedMDPName, kBackgroundButNotSummaryWhitelistedMDPName, nullptr};
+const char* const kTestMDPWhitelistForSummary[] = {kWhitelistedMDPName,
+                                                   nullptr};
+const uint64_t kTestGuid = 0;
+
+// GTest matchers for MemoryDumpRequestArgs arguments.
+MATCHER(IsDetailedDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
+}
+
+MATCHER(IsLightDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
+}
+
+MATCHER(IsBackgroundDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND;
+}
+
+// TODO(ssid): This class is replicated in memory_dump_manager_unittest. Move
+// this to memory_dump_manager_test_utils.h crbug.com/728199.
+class MockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+  MOCK_METHOD0(Destructor, void());
+  MOCK_METHOD2(OnMemoryDump,
+               bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
+  MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t* memory_total));
+  MOCK_METHOD0(SuspendFastMemoryPolling, void());
+
+  MockMemoryDumpProvider() : enable_mock_destructor(false) {
+    ON_CALL(*this, OnMemoryDump(_, _))
+        .WillByDefault(
+            Invoke([](const MemoryDumpArgs&, ProcessMemoryDump* pmd) -> bool {
+              return true;
+            }));
+
+    ON_CALL(*this, PollFastMemoryTotal(_))
+        .WillByDefault(
+            Invoke([](uint64_t* memory_total) -> void { NOTREACHED(); }));
+  }
+
+  ~MockMemoryDumpProvider() override {
+    if (enable_mock_destructor)
+      Destructor();
+  }
+
+  bool enable_mock_destructor;
+};
+
+std::unique_ptr<trace_analyzer::TraceAnalyzer> GetDeserializedTrace() {
+  // Flush the trace into JSON.
+  TraceResultBuffer buffer;
+  TraceResultBuffer::SimpleOutput trace_output;
+  buffer.SetOutputCallback(trace_output.GetCallback());
+  base::RunLoop run_loop;
+  buffer.Start();
+  auto on_trace_data_collected =
+      [](base::Closure quit_closure, TraceResultBuffer* buffer,
+         const scoped_refptr<base::RefCountedString>& json,
+         bool has_more_events) {
+        buffer->AddFragment(json->data());
+        if (!has_more_events)
+          quit_closure.Run();
+      };
+
+  TraceLog::GetInstance()->Flush(Bind(on_trace_data_collected,
+                                      run_loop.QuitClosure(),
+                                      base::Unretained(&buffer)));
+  run_loop.Run();
+  buffer.Finish();
+
+  // Analyze the JSON.
+  return base::WrapUnique(
+      trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
+}
+
+}  // namespace
+
+class MemoryTracingIntegrationTest;
+
+class MockCoordinator : public Coordinator, public mojom::Coordinator {
+ public:
+  MockCoordinator(MemoryTracingIntegrationTest* client) : client_(client) {}
+
+  void BindCoordinatorRequest(
+      const service_manager::BindSourceInfo& source_info,
+      mojom::CoordinatorRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  void RegisterClientProcess(mojom::ClientProcessPtr,
+                             mojom::ProcessType) override {}
+
+  void RequestGlobalMemoryDump(
+      const MemoryDumpRequestArgs& args,
+      const RequestGlobalMemoryDumpCallback& callback) override;
+
+ private:
+  mojo::BindingSet<mojom::Coordinator> bindings_;
+  MemoryTracingIntegrationTest* client_;
+};
+
+class MemoryTracingIntegrationTest : public testing::Test {
+ public:
+  void SetUp() override {
+    message_loop_ = base::MakeUnique<base::MessageLoop>();
+    coordinator_ = base::MakeUnique<MockCoordinator>(this);
+  }
+
+  void InitializeClientProcess(mojom::ProcessType process_type) {
+    mdm_ = MemoryDumpManager::CreateInstanceForTesting();
+    mdm_->set_dumper_registrations_ignored_for_testing(true);
+    const char* kServiceName = "TestServiceName";
+    ClientProcessImpl::Config config(nullptr, kServiceName, process_type);
+    config.coordinator_for_testing = coordinator_.get();
+    client_process_.reset(new ClientProcessImpl(config));
+  }
+
+  void TearDown() override {
+    TraceLog::GetInstance()->SetDisabled();
+    mdm_.reset();
+    client_process_.reset();
+    coordinator_.reset();
+    message_loop_.reset();
+    TraceLog::DeleteForTesting();
+  }
+
+  // Blocks the current thread (spinning a nested message loop) until the
+  // memory dump is complete. Returns:
+  // - return value: the |success| from the RequestProcessMemoryDump() callback.
+  bool RequestProcessDumpAndWait(
+      MemoryDumpType dump_type,
+      MemoryDumpLevelOfDetail level_of_detail,
+      base::Optional<MemoryDumpCallbackResult>* result = nullptr) {
+    base::RunLoop run_loop;
+    bool success = false;
+    MemoryDumpRequestArgs request_args{kTestGuid, dump_type, level_of_detail};
+    ClientProcessImpl::RequestProcessMemoryDumpCallback callback = base::Bind(
+        [](bool* curried_success, base::Closure curried_quit_closure,
+           base::Optional<MemoryDumpCallbackResult>* curried_result,
+           bool success, uint64_t dump_guid,
+           mojom::RawProcessMemoryDumpPtr result) {
+          EXPECT_EQ(kTestGuid, dump_guid);
+          *curried_success = success;
+          if (curried_result) {
+            *curried_result = MemoryDumpCallbackResult();
+            (*curried_result)->os_dump = result->os_dump;
+            (*curried_result)->chrome_dump = result->chrome_dump;
+            EXPECT_TRUE(result->extra_processes_dumps.empty());
+          }
+          curried_quit_closure.Run();
+        },
+        &success, run_loop.QuitClosure(), result);
+    client_process_->RequestProcessMemoryDump(request_args, callback);
+    run_loop.Run();
+    return success;
+  }
+
+  void RequestProcessDump(MemoryDumpType dump_type,
+                          MemoryDumpLevelOfDetail level_of_detail) {
+    MemoryDumpRequestArgs request_args{kTestGuid, dump_type, level_of_detail};
+    ClientProcessImpl::RequestProcessMemoryDumpCallback callback =
+        base::Bind([](bool success, uint64_t dump_guid,
+                      mojom::RawProcessMemoryDumpPtr result) {});
+    client_process_->RequestProcessMemoryDump(request_args, callback);
+  }
+
+ protected:
+  void EnableMemoryInfraTracing() {
+    TraceLog::GetInstance()->SetEnabled(
+        TraceConfig(MemoryDumpManager::kTraceCategory, ""),
+        TraceLog::RECORDING_MODE);
+  }
+
+  void EnableMemoryInfraTracingWithTraceConfig(
+      const std::string& trace_config) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      const MemoryDumpProvider::Options& options,
+      const char* name = kMDPName) {
+    mdm_->set_dumper_registrations_ignored_for_testing(false);
+    mdm_->RegisterDumpProvider(mdp, name, std::move(task_runner), options);
+    mdm_->set_dumper_registrations_ignored_for_testing(true);
+  }
+
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    RegisterDumpProvider(mdp, task_runner, MemoryDumpProvider::Options());
+  }
+
+  bool IsPeriodicDumpingEnabled() const {
+    return MemoryDumpScheduler::GetInstance()->is_enabled_for_testing();
+  }
+
+  std::unique_ptr<MemoryDumpManager> mdm_;
+
+ private:
+  std::unique_ptr<base::MessageLoop> message_loop_;
+  std::unique_ptr<MockCoordinator> coordinator_;
+  std::unique_ptr<ClientProcessImpl> client_process_;
+};
+
+void MockCoordinator::RequestGlobalMemoryDump(
+    const MemoryDumpRequestArgs& args,
+    const RequestGlobalMemoryDumpCallback& callback) {
+  client_->RequestProcessDump(args.dump_type, args.level_of_detail);
+  callback.Run(args.dump_guid, true, mojom::GlobalMemoryDumpPtr());
+}
+
+// Tests that the MemoryDumpProvider(s) are invoked even if tracing has not
+// been initialized.
+TEST_F(MemoryTracingIntegrationTest, DumpWithoutInitializingTracing) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp, base::ThreadTaskRunnerHandle::Get(),
+                       MemoryDumpProvider::Options());
+  DisableTracing();
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
+  for (int i = 0; i < 3; ++i) {
+    // A non-SUMMARY_ONLY dump was requested when tracing was not enabled. So,
+    // the request should fail because dump was not added to the trace.
+    EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                           MemoryDumpLevelOfDetail::DETAILED));
+  }
+  mdm_->UnregisterDumpProvider(&mdp);
+}
+
+// Similar to DumpWithoutInitializingTracing. Tracing is initialized but not
+// enabled.
+TEST_F(MemoryTracingIntegrationTest,
+       DumpWithMDMInitializedForTracingButDisabled) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp, base::ThreadTaskRunnerHandle::Get(),
+                       MemoryDumpProvider::Options());
+
+  DisableTracing();
+
+  const TraceConfig& trace_config =
+      TraceConfig(base::trace_event::TraceConfigMemoryTestUtil::
+                      GetTraceConfig_NoTriggers());
+  const TraceConfig::MemoryDumpConfig& memory_dump_config =
+      trace_config.memory_dump_config();
+  mdm_->SetupForTracing(memory_dump_config);
+
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3);
+  for (int i = 0; i < 3; ++i) {
+    // Same as the above. Even if the MDP(s) are invoked, this will return false
+    // while attempting to add the dump into the trace.
+    EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                           MemoryDumpLevelOfDetail::DETAILED));
+  }
+  mdm_->TeardownForTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+}
+
+TEST_F(MemoryTracingIntegrationTest, SummaryOnlyDumpsArentAddedToTrace) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  using trace_analyzer::Query;
+
+  base::trace_event::SetDumpProviderSummaryWhitelistForTesting(
+      kTestMDPWhitelistForSummary);
+  base::trace_event::SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
+
+  // Standard provider with default options (create dump for current process).
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp, nullptr, MemoryDumpProvider::Options(),
+                       kWhitelistedMDPName);
+
+  EnableMemoryInfraTracing();
+
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(2);
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::BACKGROUND));
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
+                                        MemoryDumpLevelOfDetail::BACKGROUND));
+  DisableTracing();
+
+  std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
+      GetDeserializedTrace();
+  trace_analyzer::TraceEventVector events;
+  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+                       &events);
+
+  ASSERT_EQ(1u, events.size());
+  ASSERT_TRUE(trace_analyzer::CountMatches(
+      events, Query::EventNameIs(MemoryDumpTypeToString(
+                  MemoryDumpType::EXPLICITLY_TRIGGERED))));
+}
+
+// Checks that is the ClientProcessImpl is initialized after tracing already
+// began, it will still late-join the party (real use case: startup tracing).
+TEST_F(MemoryTracingIntegrationTest, InitializedAfterStartOfTracing) {
+  EnableMemoryInfraTracing();
+
+  // TODO(ssid): Add tests for
+  // MemoryInstrumentation::RequestGlobalDumpAndAppendToTrace to fail gracefully
+  // before creating ClientProcessImpl.
+
+  // Now late-initialize and check that the CreateProcessDump() completes
+  // successfully.
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp, nullptr, MemoryDumpProvider::Options());
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::DETAILED));
+  DisableTracing();
+}
+
+// Configures periodic dumps with MemoryDumpLevelOfDetail::BACKGROUND triggers
+// and tests that only BACKGROUND are added to the trace, but not LIGHT or
+// DETAILED, even if requested explicitly.
+TEST_F(MemoryTracingIntegrationTest, TestBackgroundTracingSetup) {
+  InitializeClientProcess(mojom::ProcessType::BROWSER);
+  base::trace_event::SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
+  auto mdp = base::MakeUnique<MockMemoryDumpProvider>();
+  RegisterDumpProvider(&*mdp, nullptr, MemoryDumpProvider::Options(),
+                       kWhitelistedMDPName);
+
+  base::RunLoop run_loop;
+  auto test_task_runner = base::ThreadTaskRunnerHandle::Get();
+  auto quit_closure = run_loop.QuitClosure();
+
+  {
+    testing::InSequence sequence;
+    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _))
+        .Times(3)
+        .WillRepeatedly(Invoke(
+            [](const MemoryDumpArgs&, ProcessMemoryDump*) { return true; }));
+    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _))
+        .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
+                                                          ProcessMemoryDump*) {
+          test_task_runner->PostTask(FROM_HERE, quit_closure);
+          return true;
+        }));
+    EXPECT_CALL(*mdp, OnMemoryDump(IsBackgroundDump(), _)).Times(AnyNumber());
+  }
+
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_BackgroundTrigger(1 /* period_ms */));
+
+  run_loop.Run();
+
+  // When requesting non-BACKGROUND dumps the MDP will be invoked but the
+  // data is expected to be dropped on the floor, hence the EXPECT_FALSE.
+  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _));
+  EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                         MemoryDumpLevelOfDetail::LIGHT));
+
+  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
+  EXPECT_FALSE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                         MemoryDumpLevelOfDetail::DETAILED));
+
+  ASSERT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
+}
+
+// This test (and the TraceConfigExpectationsWhenIsCoordinator below)
+// crystallizes the expectations of the chrome://tracing UI and chrome telemetry
+// w.r.t. periodic dumps in memory-infra, handling gracefully the transition
+// between the legacy and the new-style (JSON-based) TraceConfig.
+TEST_F(MemoryTracingIntegrationTest, TraceConfigExpectations) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+
+  // We don't need to create any dump in this test, only check whether the dumps
+  // are requested or not.
+
+  // Enabling memory-infra in a non-coordinator process should not trigger any
+  // periodic dumps.
+  EnableMemoryInfraTracing();
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
+  // process with a fully defined trigger config should NOT enable any periodic
+  // dumps.
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_PeriodicTriggers(1, 5));
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+}
+
+TEST_F(MemoryTracingIntegrationTest, TraceConfigExpectationsWhenIsCoordinator) {
+  InitializeClientProcess(mojom::ProcessType::BROWSER);
+
+  // Enabling memory-infra with the legacy TraceConfig (category filter) in
+  // a coordinator process should not enable periodic dumps.
+  EnableMemoryInfraTracing();
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process while specifying a "memory_dump_config" section should enable
+  // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
+  // is: ticking memory-infra should dump periodically with an explicit config.
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_PeriodicTriggers(100, 5));
+
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with an empty "memory_dump_config" should NOT enable periodic
+  // dumps. This is the way telemetry is supposed to use memory-infra with
+  // only explicitly triggered dumps.
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_EmptyTriggers());
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+}
+
+TEST_F(MemoryTracingIntegrationTest, PeriodicDumpingWithMultipleModes) {
+  InitializeClientProcess(mojom::ProcessType::BROWSER);
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with a fully defined trigger config should cause periodic dumps to
+  // be performed in the correct order.
+  base::RunLoop run_loop;
+  auto test_task_runner = base::ThreadTaskRunnerHandle::Get();
+  auto quit_closure = run_loop.QuitClosure();
+
+  const int kHeavyDumpRate = 5;
+  const int kLightDumpPeriodMs = 1;
+  const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
+
+  // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
+  auto mdp = base::MakeUnique<MockMemoryDumpProvider>();
+  RegisterDumpProvider(&*mdp, nullptr, MemoryDumpProvider::Options(),
+                       kWhitelistedMDPName);
+
+  testing::InSequence sequence;
+  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 1);
+  EXPECT_CALL(*mdp, OnMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _)).Times(kHeavyDumpRate - 2);
+  EXPECT_CALL(*mdp, OnMemoryDump(IsLightDump(), _))
+      .WillOnce(Invoke([test_task_runner, quit_closure](const MemoryDumpArgs&,
+                                                        ProcessMemoryDump*) {
+        test_task_runner->PostTask(FROM_HERE, quit_closure);
+        return true;
+      }));
+
+  // Swallow all the final spurious calls until tracing gets disabled.
+  EXPECT_CALL(*mdp, OnMemoryDump(_, _)).Times(AnyNumber());
+
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_PeriodicTriggers(kLightDumpPeriodMs,
+                                          kHeavyDumpPeriodMs));
+  run_loop.Run();
+  DisableTracing();
+  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp));
+}
+
+TEST_F(MemoryTracingIntegrationTest, TestWhitelistingMDP) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  base::trace_event::SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
+  std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
+  RegisterDumpProvider(mdp1.get(), nullptr);
+  std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
+  RegisterDumpProvider(mdp2.get(), nullptr, MemoryDumpProvider::Options(),
+                       kWhitelistedMDPName);
+
+  EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1);
+
+  EnableMemoryInfraTracing();
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::BACKGROUND));
+  DisableTracing();
+}
+
+TEST_F(MemoryTracingIntegrationTest, TestSummaryComputation) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp, base::ThreadTaskRunnerHandle::Get(),
+                       MemoryDumpProvider::Options());
+
+  EXPECT_CALL(mdp, OnMemoryDump(_, _))
+      .WillOnce(Invoke([](const MemoryDumpArgs&,
+                          ProcessMemoryDump* pmd) -> bool {
+        auto* size = MemoryAllocatorDump::kNameSize;
+        auto* bytes = MemoryAllocatorDump::kUnitsBytes;
+        const uint32_t kB = 1024;
+
+        pmd->CreateAllocatorDump("malloc")->AddScalar(size, bytes, 1 * kB);
+        pmd->CreateAllocatorDump("malloc/ignored")
+            ->AddScalar(size, bytes, 99 * kB);
+
+        pmd->CreateAllocatorDump("blink_gc")->AddScalar(size, bytes, 2 * kB);
+        pmd->CreateAllocatorDump("blink_gc/ignored")
+            ->AddScalar(size, bytes, 99 * kB);
+
+        pmd->CreateAllocatorDump("v8/foo")->AddScalar(size, bytes, 1 * kB);
+        pmd->CreateAllocatorDump("v8/bar")->AddScalar(size, bytes, 2 * kB);
+        pmd->CreateAllocatorDump("v8")->AddScalar(size, bytes, 99 * kB);
+
+        // All the 99 KB values here are expected to be ignored.
+        pmd->CreateAllocatorDump("partition_alloc")
+            ->AddScalar(size, bytes, 99 * kB);
+        pmd->CreateAllocatorDump("partition_alloc/allocated_objects")
+            ->AddScalar(size, bytes, 99 * kB);
+        pmd->CreateAllocatorDump("partition_alloc/allocated_objects/ignored")
+            ->AddScalar(size, bytes, 99 * kB);
+        pmd->CreateAllocatorDump("partition_alloc/partitions")
+            ->AddScalar(size, bytes, 99 * kB);
+        pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_1")
+            ->AddScalar(size, bytes, 2 * kB);
+        pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_2")
+            ->AddScalar(size, bytes, 2 * kB);
+        pmd->process_totals()->set_resident_set_bytes(5 * kB);
+        pmd->set_has_process_totals();
+        return true;
+      }));
+
+  EnableMemoryInfraTracing();
+  base::Optional<MemoryDumpCallbackResult> result;
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::LIGHT,
+                                        &result));
+  DisableTracing();
+
+  ASSERT_TRUE(result);
+
+  // For malloc we only count the root "malloc" not children "malloc/*".
+  EXPECT_EQ(1u, result->chrome_dump.malloc_total_kb);
+
+  // For blink_gc we only count the root "blink_gc" not children "blink_gc/*".
+  EXPECT_EQ(2u, result->chrome_dump.blink_gc_total_kb);
+
+  // For v8 we count the children ("v8/*") as the root total is not given.
+  EXPECT_EQ(3u, result->chrome_dump.v8_total_kb);
+
+  // partition_alloc has partition_alloc/allocated_objects/* which is a subset
+  // of partition_alloc/partitions/* so we only count the latter.
+  EXPECT_EQ(4u, result->chrome_dump.partition_alloc_total_kb);
+
+  // resident_set_kb should read from process_totals.
+  EXPECT_EQ(5u, result->os_dump.resident_set_kb);
+};
+
+TEST_F(MemoryTracingIntegrationTest, DumpOnBehalfOfOtherProcess) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  using trace_analyzer::Query;
+
+  // Standard provider with default options (create dump for current process).
+  MemoryDumpProvider::Options options;
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1, nullptr, options);
+
+  // Provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp2;
+  options.target_pid = 123;
+  RegisterDumpProvider(&mdp2, nullptr, options);
+
+  // Another provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp3;
+  options.target_pid = 456;
+  RegisterDumpProvider(&mdp3, nullptr, options);
+
+  EnableMemoryInfraTracing();
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1);
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::DETAILED));
+  DisableTracing();
+
+  std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
+      GetDeserializedTrace();
+  trace_analyzer::TraceEventVector events;
+  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+                       &events);
+
+  ASSERT_EQ(3u, events.size());
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(
+                    events, Query::EventPidIs(base::GetCurrentProcId())));
+  ASSERT_EQ(events[0]->id, events[1]->id);
+  ASSERT_EQ(events[0]->id, events[2]->id);
+}
+
+TEST_F(MemoryTracingIntegrationTest, TestPollingOnDumpThread) {
+  InitializeClientProcess(mojom::ProcessType::RENDERER);
+  std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider());
+  std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider());
+  mdp1->enable_mock_destructor = true;
+  mdp2->enable_mock_destructor = true;
+  EXPECT_CALL(*mdp1, Destructor());
+  EXPECT_CALL(*mdp2, Destructor());
+
+  MemoryDumpProvider::Options options;
+  options.is_fast_polling_supported = true;
+  RegisterDumpProvider(mdp1.get(), nullptr, options);
+
+  base::RunLoop run_loop;
+  auto test_task_runner = base::ThreadTaskRunnerHandle::Get();
+  auto quit_closure = run_loop.QuitClosure();
+  MemoryDumpManager* mdm = mdm_.get();
+
+  EXPECT_CALL(*mdp1, PollFastMemoryTotal(_))
+      .WillOnce(Invoke([&mdp2, options, this](uint64_t*) {
+        RegisterDumpProvider(mdp2.get(), nullptr, options);
+      }))
+      .WillOnce(Return())
+      .WillOnce(Invoke([mdm, &mdp2](uint64_t*) {
+        mdm->UnregisterAndDeleteDumpProviderSoon(std::move(mdp2));
+      }))
+      .WillOnce(Invoke([test_task_runner, quit_closure](uint64_t*) {
+        test_task_runner->PostTask(FROM_HERE, quit_closure);
+      }))
+      .WillRepeatedly(Return());
+
+  // We expect a call to |mdp1| because it is still registered at the time the
+  // Peak detector is Stop()-ed (upon OnTraceLogDisabled(). We do NOT expect
+  // instead a call for |mdp2|, because that gets unregisterd before the Stop().
+  EXPECT_CALL(*mdp1, SuspendFastMemoryPolling()).Times(1);
+  EXPECT_CALL(*mdp2, SuspendFastMemoryPolling()).Times(0);
+
+  // |mdp2| should invoke exactly twice:
+  // - once after the registrarion, when |mdp1| hits the first Return()
+  // - the 2nd time when |mdp1| unregisters |mdp1|. The unregistration is
+  //   posted and will necessarily happen after the polling task.
+  EXPECT_CALL(*mdp2, PollFastMemoryTotal(_)).Times(2).WillRepeatedly(Return());
+
+  EnableMemoryInfraTracingWithTraceConfig(
+      base::trace_event::TraceConfigMemoryTestUtil::
+          GetTraceConfig_PeakDetectionTrigger(1));
+  run_loop.Run();
+  DisableTracing();
+  mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdp1));
+}
+
+}  // namespace memory_instrumentation
diff --git a/services/service_manager/public/interfaces/service_manager.mojom b/services/service_manager/public/interfaces/service_manager.mojom
index d97bc544..de06ed7 100644
--- a/services/service_manager/public/interfaces/service_manager.mojom
+++ b/services/service_manager/public/interfaces/service_manager.mojom
@@ -30,6 +30,9 @@
   // assigned to it.
   OnServiceStarted(Identity identity, uint32 pid);
 
+  // Called when a pid is available for the service.
+  OnServicePIDReceived(Identity identity, uint32 pid);
+
   // Called when a service failed to start. (typically because it was shutdown
   // before the manager heard back from the service).
   OnServiceFailedToStart(Identity identity);
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index 1f9d3fd..429bbb1 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -612,6 +612,7 @@
     }
 #endif
     pid_ = pid;
+    service_manager_->NotifyServicePIDReceived(identity_, pid_);
   }
 
   void OnServiceLost(
@@ -976,7 +977,7 @@
 }
 
 void ServiceManager::OnInstanceStopped(const Identity& identity) {
-  listeners_.ForAllPtrs([identity](mojom::ServiceManagerListener* listener) {
+  listeners_.ForAllPtrs([&identity](mojom::ServiceManagerListener* listener) {
     listener->OnServiceStopped(identity);
   });
   if (!instance_quit_callback_.is_null())
@@ -1026,15 +1027,22 @@
 void ServiceManager::NotifyServiceStarted(const Identity& identity,
                                           base::ProcessId pid) {
   listeners_.ForAllPtrs(
-      [identity, pid](mojom::ServiceManagerListener* listener) {
+      [&identity, pid](mojom::ServiceManagerListener* listener) {
         listener->OnServiceStarted(identity, pid);
       });
 }
 
 void ServiceManager::NotifyServiceFailedToStart(const Identity& identity) {
+  listeners_.ForAllPtrs([&identity](mojom::ServiceManagerListener* listener) {
+    listener->OnServiceFailedToStart(identity);
+  });
+}
+
+void ServiceManager::NotifyServicePIDReceived(const Identity& identity,
+                                              base::ProcessId pid) {
   listeners_.ForAllPtrs(
-      [identity](mojom::ServiceManagerListener* listener) {
-        listener->OnServiceFailedToStart(identity);
+      [&identity, pid](mojom::ServiceManagerListener* listener) {
+        listener->OnServicePIDReceived(identity, pid);
       });
 }
 
diff --git a/services/service_manager/service_manager.h b/services/service_manager/service_manager.h
index 2469c95e..44c6ae44 100644
--- a/services/service_manager/service_manager.h
+++ b/services/service_manager/service_manager.h
@@ -121,6 +121,8 @@
   void NotifyServiceStarted(const Identity& identity, base::ProcessId pid);
   void NotifyServiceFailedToStart(const Identity& identity);
 
+  void NotifyServicePIDReceived(const Identity& identity, base::ProcessId pid);
+
   // Attempt to complete the connection requested by |params| by connecting to
   // an existing instance. If there is an existing instance, |params| is taken,
   // and this function returns true.
diff --git a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
index 1e2c9a1..9ae62ba7 100644
--- a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
+++ b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
@@ -110,6 +110,15 @@
       destruction_loop_ = nullptr;
     }
   }
+  void OnServicePIDReceived(const service_manager::Identity& identity,
+                            uint32_t pid) override {
+    for (auto& instance : instances_) {
+      if (instance.second.identity == identity) {
+        instance.second.pid = pid;
+        break;
+      }
+    }
+  }
 
   // All currently running instances.
   std::map<std::string, Instance> instances_;
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest.cc b/services/service_manager/tests/service_manager/service_manager_unittest.cc
index 5d0d229..11b4597 100644
--- a/services/service_manager/tests/service_manager/service_manager_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_unittest.cc
@@ -154,6 +154,13 @@
     service_failed_to_start_callback_ = callback;
   }
 
+  using ServicePIDReceivedCallback =
+      base::Callback<void(const service_manager::Identity&, uint32_t pid)>;
+  void set_service_pid_received_callback(
+      const ServicePIDReceivedCallback& callback) {
+    service_pid_received_callback_ = callback;
+  }
+
   void StartTarget() {
     base::FilePath target_path;
     CHECK(base::PathService::Get(base::DIR_EXE, &target_path));
@@ -256,6 +263,11 @@
       }
     }
   }
+  void OnServicePIDReceived(const service_manager::Identity& identity,
+                            uint32_t pid) override {
+    if (!service_pid_received_callback_.is_null())
+      service_pid_received_callback_.Run(identity, pid);
+  }
 
   void OnConnectionCompleted(mojom::ConnectResult, const Identity&) {}
 
@@ -266,6 +278,7 @@
   std::unique_ptr<base::RunLoop> wait_for_instances_loop_;
   ServiceStartedCallback service_started_callback_;
   ServiceFailedToStartCallback service_failed_to_start_callback_;
+  ServicePIDReceivedCallback service_pid_received_callback_;
   base::Process target_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceManagerTest);
@@ -318,6 +331,16 @@
   continuation.Run();
 }
 
+void OnServicePIDReceivedCallback(std::string* service_name,
+                                  uint32_t* serivce_pid,
+                                  const base::Closure& continuation,
+                                  const service_manager::Identity& identity,
+                                  uint32_t pid) {
+  *service_name = identity.name();
+  *serivce_pid = pid;
+  continuation.Run();
+}
+
 // Tests that creating connecting to a singleton packaged service work.
 TEST_F(ServiceManagerTest, CreatePackagedSingletonInstance) {
   AddListenerAndWaitForApplications();
@@ -363,4 +386,26 @@
   }
 }
 
+TEST_F(ServiceManagerTest, PIDReceivedCallback) {
+  AddListenerAndWaitForApplications();
+
+  {
+    base::RunLoop loop;
+    std::string service_name;
+    uint32_t pid = 0u;
+    set_service_pid_received_callback(
+        base::BindRepeating(&OnServicePIDReceivedCallback, &service_name, &pid,
+                            loop.QuitClosure()));
+    bool failed_to_start = false;
+    set_service_failed_to_start_callback(base::BindRepeating(
+        &OnServiceFailedToStartCallback, &failed_to_start, loop.QuitClosure()));
+
+    connector()->StartService("service_manager_unittest_embedder");
+    loop.Run();
+    EXPECT_FALSE(failed_to_start);
+    EXPECT_EQ("service_manager_unittest_embedder", service_name);
+    EXPECT_NE(pid, 0u);
+  }
+}
+
 }  // namespace service_manager
diff --git a/services/shape_detection/barcode_detection_impl_mac.mm b/services/shape_detection/barcode_detection_impl_mac.mm
index a3df01e2..6aa128f 100644
--- a/services/shape_detection/barcode_detection_impl_mac.mm
+++ b/services/shape_detection/barcode_detection_impl_mac.mm
@@ -37,9 +37,11 @@
 
 BarcodeDetectionImplMac::BarcodeDetectionImplMac() {
   NSDictionary* const options = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
-  detector_.reset([[CIDetector detectorOfType:CIDetectorTypeQRCode
-                                      context:nil
-                                      options:options] retain]);
+  if (@available(macOS 10.10, *)) {
+    detector_.reset([[CIDetector detectorOfType:CIDetectorTypeQRCode
+                                        context:nil
+                                        options:options] retain]);
+  }
 }
 
 BarcodeDetectionImplMac::~BarcodeDetectionImplMac() {}
diff --git a/services/ui/gpu/gpu_service.cc b/services/ui/gpu/gpu_service.cc
index f1dcb08..d466940 100644
--- a/services/ui/gpu/gpu_service.cc
+++ b/services/ui/gpu/gpu_service.cc
@@ -222,6 +222,20 @@
   (*gpu_host_)->RecordLogMessage(severity, header, message);
 }
 
+void GpuService::CreateJpegDecodeAccelerator(
+    media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
+  DCHECK(io_runner_->BelongsToCurrentThread());
+  // TODO(c.padhi): Implement this, see https://crbug.com/699255.
+  NOTIMPLEMENTED();
+}
+
+void GpuService::CreateVideoEncodeAccelerator(
+    media::mojom::VideoEncodeAcceleratorRequest vea_request) {
+  DCHECK(io_runner_->BelongsToCurrentThread());
+  // TODO(mcasas): Create a mojom::VideoEncodeAccelerator implementation,
+  // https://crbug.com/736517.
+}
+
 void GpuService::CreateGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     const gfx::Size& size,
diff --git a/services/ui/gpu/gpu_service.h b/services/ui/gpu/gpu_service.h
index 21b6c24e..def7f70 100644
--- a/services/ui/gpu/gpu_service.h
+++ b/services/ui/gpu/gpu_service.h
@@ -134,6 +134,10 @@
       bool is_gpu_host,
       const EstablishGpuChannelCallback& callback) override;
   void CloseChannel(int32_t client_id) override;
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override;
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request) override;
   void CreateGpuMemoryBuffer(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
diff --git a/services/ui/gpu/interfaces/BUILD.gn b/services/ui/gpu/interfaces/BUILD.gn
index ac54c96..98cf0efe 100644
--- a/services/ui/gpu/interfaces/BUILD.gn
+++ b/services/ui/gpu/interfaces/BUILD.gn
@@ -15,6 +15,8 @@
   public_deps = [
     "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
+    "//media/gpu/mojo:jpeg_decoder",
+    "//media/mojo/interfaces",
     "//services/ui/public/interfaces",
     "//ui/gfx/geometry/mojo",
     "//ui/gfx/mojo",
diff --git a/services/ui/gpu/interfaces/gpu_service.mojom b/services/ui/gpu/interfaces/gpu_service.mojom
index 27fe4df..b4020f6 100644
--- a/services/ui/gpu/interfaces/gpu_service.mojom
+++ b/services/ui/gpu/interfaces/gpu_service.mojom
@@ -8,6 +8,8 @@
 import "gpu/ipc/common/memory_stats.mojom";
 import "gpu/ipc/common/surface_handle.mojom";
 import "gpu/ipc/common/sync_token.mojom";
+import "media/gpu/mojo/jpeg_decoder.mojom";
+import "media/mojo/interfaces/video_encode_accelerator.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/buffer_types.mojom";
 
@@ -23,6 +25,12 @@
   // If no channel can be identified, do nothing.
   CloseChannel(int32 client_id);
 
+  // Creates a new JpegDecodeAccelerator and binds it to |jda|.
+  CreateJpegDecodeAccelerator(media.mojom.GpuJpegDecodeAccelerator& jda);
+
+  // Creates a new VideoEncodeAccelerator and binds it to |vea|.
+  CreateVideoEncodeAccelerator(media.mojom.VideoEncodeAccelerator& vea);
+
   CreateGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferId id,
                         gfx.mojom.Size size,
                         gfx.mojom.BufferFormat format,
diff --git a/services/ui/public/cpp/gpu/gpu.cc b/services/ui/public/cpp/gpu/gpu.cc
index 82c392f..191633e 100644
--- a/services/ui/public/cpp/gpu/gpu.cc
+++ b/services/ui/public/cpp/gpu/gpu.cc
@@ -90,6 +90,22 @@
       shared_context_provider, ui::command_buffer_metrics::MUS_CLIENT_CONTEXT));
 }
 
+void Gpu::CreateJpegDecodeAccelerator(
+    media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
+  DCHECK(IsMainThread());
+  if (!gpu_ || !gpu_.is_bound())
+    gpu_ = factory_.Run();
+  gpu_->CreateJpegDecodeAccelerator(std::move(jda_request));
+}
+
+void Gpu::CreateVideoEncodeAccelerator(
+    media::mojom::VideoEncodeAcceleratorRequest vea_request) {
+  DCHECK(IsMainThread());
+  if (!gpu_ || !gpu_.is_bound())
+    gpu_ = factory_.Run();
+  gpu_->CreateVideoEncodeAccelerator(std::move(vea_request));
+}
+
 void Gpu::EstablishGpuChannel(
     const gpu::GpuChannelEstablishedCallback& callback) {
   DCHECK(IsMainThread());
@@ -98,11 +114,15 @@
     callback.Run(std::move(channel));
     return;
   }
+
+  const bool gpu_channel_request_ongoing = !establish_callbacks_.empty();
+  // Cache |callback| but don't launch more than one EstablishGpuChannel().
   establish_callbacks_.push_back(callback);
-  if (gpu_)
+  if (gpu_channel_request_ongoing)
     return;
 
-  gpu_ = factory_.Run();
+  if (!gpu_ || !gpu_.is_bound())
+    gpu_ = factory_.Run();
   gpu_->EstablishGpuChannel(
       base::Bind(&Gpu::OnEstablishedGpuChannel, base::Unretained(this)));
 }
@@ -111,18 +131,19 @@
   DCHECK(IsMainThread());
   if (GetGpuChannel())
     return gpu_channel_;
+  if (!gpu_ || !gpu_.is_bound())
+    gpu_ = factory_.Run();
 
   int client_id = 0;
   mojo::ScopedMessagePipeHandle channel_handle;
   gpu::GPUInfo gpu_info;
-  gpu_ = factory_.Run();
   mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
   if (!gpu_->EstablishGpuChannel(&client_id, &channel_handle, &gpu_info)) {
-    DLOG(WARNING)
-        << "Channel encountered error while establishing gpu channel.";
+    DLOG(WARNING) << "Encountered error while establishing gpu channel.";
     return nullptr;
   }
   OnEstablishedGpuChannel(client_id, std::move(channel_handle), gpu_info);
+
   return gpu_channel_;
 }
 
@@ -152,7 +173,6 @@
         &shutdown_event_, gpu_memory_buffer_manager_.get());
   }
 
-  gpu_.reset();
   auto callbacks = std::move(establish_callbacks_);
   establish_callbacks_.clear();
   for (const auto& callback : callbacks)
diff --git a/services/ui/public/cpp/gpu/gpu.h b/services/ui/public/cpp/gpu/gpu.h
index 4b506e2..73459fc04 100644
--- a/services/ui/public/cpp/gpu/gpu.h
+++ b/services/ui/public/cpp/gpu/gpu.h
@@ -44,6 +44,11 @@
   scoped_refptr<cc::ContextProvider> CreateContextProvider(
       scoped_refptr<gpu::GpuChannelHost> gpu_channel);
 
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request);
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request);
+
   // gpu::GpuChannelEstablishFactory:
   void EstablishGpuChannel(
       const gpu::GpuChannelEstablishedCallback& callback) override;
diff --git a/services/ui/public/cpp/tests/gpu_unittest.cc b/services/ui/public/cpp/tests/gpu_unittest.cc
index 9d816a4d..7a5ff38 100644
--- a/services/ui/public/cpp/tests/gpu_unittest.cc
+++ b/services/ui/public/cpp/tests/gpu_unittest.cc
@@ -53,6 +53,12 @@
       quit_closure_.Run();
   }
 
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override {}
+
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request) override {}
+
   void CreateGpuMemoryBuffer(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
diff --git a/services/ui/public/interfaces/BUILD.gn b/services/ui/public/interfaces/BUILD.gn
index 809b9d70..4495e4f 100644
--- a/services/ui/public/interfaces/BUILD.gn
+++ b/services/ui/public/interfaces/BUILD.gn
@@ -33,6 +33,8 @@
     ":constants",
     "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
+    "//media/gpu/mojo:jpeg_decoder",
+    "//media/mojo/interfaces",
     "//services/ui/public/interfaces/cursor",
     "//services/ui/public/interfaces/display",
     "//services/ui/public/interfaces/ime",
diff --git a/services/ui/public/interfaces/gpu.mojom b/services/ui/public/interfaces/gpu.mojom
index 552b9ebc9d..6bbd3b3 100644
--- a/services/ui/public/interfaces/gpu.mojom
+++ b/services/ui/public/interfaces/gpu.mojom
@@ -6,6 +6,8 @@
 
 import "gpu/ipc/common/gpu_info.mojom";
 import "gpu/ipc/common/sync_token.mojom";
+import "media/gpu/mojo/jpeg_decoder.mojom";
+import "media/mojo/interfaces/video_encode_accelerator.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/buffer_types.mojom";
 
@@ -18,6 +20,12 @@
                             handle<message_pipe>? channel_handle,
                             gpu.mojom.GpuInfo gpu_info);
 
+  // Creates a new JpegDecodeAccelerator and binds it to |jda|.
+  CreateJpegDecodeAccelerator(media.mojom.GpuJpegDecodeAccelerator& jda);
+
+  // Creates a new VideoEncodeAccelerator and binds it to |vea|.
+  CreateVideoEncodeAccelerator(media.mojom.VideoEncodeAccelerator& vea);
+
   // Tells the GPU service to create a new GPU memory buffer.
   CreateGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferId id,
                         gfx.mojom.Size size,
diff --git a/services/ui/ws/gpu_client.cc b/services/ui/ws/gpu_client.cc
index 94f38c42..6deacf98 100644
--- a/services/ui/ws/gpu_client.cc
+++ b/services/ui/ws/gpu_client.cc
@@ -56,6 +56,16 @@
                  weak_factory_.GetWeakPtr(), callback));
 }
 
+void GpuClient::CreateJpegDecodeAccelerator(
+    media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) {
+  gpu_service_->CreateJpegDecodeAccelerator(std::move(jda_request));
+}
+
+void GpuClient::CreateVideoEncodeAccelerator(
+    media::mojom::VideoEncodeAcceleratorRequest vea_request) {
+  NOTIMPLEMENTED();
+}
+
 void GpuClient::CreateGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     const gfx::Size& size,
diff --git a/services/ui/ws/gpu_client.h b/services/ui/ws/gpu_client.h
index 23b3fc5..ea3a106 100644
--- a/services/ui/ws/gpu_client.h
+++ b/services/ui/ws/gpu_client.h
@@ -44,6 +44,10 @@
   // mojom::Gpu overrides:
   void EstablishGpuChannel(
       const EstablishGpuChannelCallback& callback) override;
+  void CreateJpegDecodeAccelerator(
+      media::mojom::GpuJpegDecodeAcceleratorRequest jda_request) override;
+  void CreateVideoEncodeAccelerator(
+      media::mojom::VideoEncodeAcceleratorRequest vea_request) override;
   void CreateGpuMemoryBuffer(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
diff --git a/services/video_capture/test/device_factory_provider_test.h b/services/video_capture/test/device_factory_provider_test.h
index 7dcd968..49e63e25 100644
--- a/services/video_capture/test/device_factory_provider_test.h
+++ b/services/video_capture/test/device_factory_provider_test.h
@@ -34,6 +34,8 @@
                         uint32_t pid) override {}
   void OnServiceFailedToStart(
       const service_manager::Identity& identity) override {}
+  void OnServicePIDReceived(const service_manager::Identity& identity,
+                            uint32_t pid) override {}
 
   MOCK_METHOD1(OnServiceStopped,
                void(const service_manager::Identity& identity));
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..1bc54dd1 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": [
@@ -3674,7 +3746,8 @@
           "can_use_on_swarming_builders": true,
           "shards": 5
         },
-        "test": "browser_tests"
+        "test": "browser_tests",
+        "upload_to_flake_predictor": true
       },
       {
         "args": [
@@ -4198,6 +4271,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -4882,6 +4961,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "wm_unittests"
       }
     ],
@@ -5265,6 +5350,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 0949bf09..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/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index efa8894..973a15dc 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1581,6 +1581,25 @@
             ]
         }
     ],
+    "NTPCaptureThumbnailOnLoadFinished": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "CaptureThumbnailDependingOnTransitionType",
+                        "CaptureThumbnailOnLoadFinished"
+                    ]
+                }
+            ]
+        }
+    ],
     "NTPFaviconsFromNewServer": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index e61a712..867450f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -229,21 +229,21 @@
 crbug.com/591099 animations/3d/change-transform-in-end-event.html [ Failure Pass ]
 crbug.com/591099 animations/3d/state-at-end-event-transform.html [ Failure Pass ]
 crbug.com/591099 animations/animation-css-rule-types.html [ Failure ]
-crbug.com/591099 animations/animation-events-create.html [ Failure ]
+crbug.com/591099 animations/events/animation-events-create.html [ Failure ]
 crbug.com/591099 animations/animations-parsing.html [ Timeout ]
-crbug.com/591099 animations/animations-responsive-to-color-change.html [ Crash Pass ]
-crbug.com/591099 animations/clear-svg-animation-effects.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/animations-responsive-to-color-change.html [ Crash Pass ]
+crbug.com/591099 animations/svg/clear-svg-animation-effects.html [ Crash Pass ]
 crbug.com/591099 animations/composition/background-position-composition.html [ Crash Pass ]
 crbug.com/591099 animations/composition/caret-color-composition.html [ Crash Pass ]
 crbug.com/591099 animations/composition/stroke-dasharray-composition.html [ Crash Pass ]
 crbug.com/591099 animations/computed-style.html [ Failure ]
-crbug.com/591099 animations/css-animation-overrides-svg-presentation-attribute-animation.html [ Crash Pass ]
-crbug.com/591099 animations/delay-start-event.html [ Failure ]
+crbug.com/591099 animations/svg/css-animation-overrides-svg-presentation-attribute-animation.html [ Crash Pass ]
+crbug.com/591099 animations/events/delay-start-event.html [ Failure ]
 crbug.com/591099 animations/display-change-does-not-terminate-animation.html [ Crash Failure ]
 crbug.com/591099 animations/display-inline-style-adjust.html [ Failure ]
 crbug.com/591099 animations/display-none-cancel-computedstyle.html [ Failure ]
 crbug.com/591099 animations/display-none-terminates-animation.html [ Failure ]
-crbug.com/591099 animations/inline-element-animation-end-hit-test.html [ Failure ]
+crbug.com/591099 animations/hit-testing/inline-element-animation-end-hit-test.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Crash Timeout ]
 crbug.com/591099 animations/interpolation/background-color-interpolation.html [ Crash Pass ]
 crbug.com/591099 animations/interpolation/background-image-interpolation.html [ Crash Timeout ]
@@ -330,14 +330,14 @@
 crbug.com/591099 animations/interpolation/webkit-transform-origin-interpolation.html [ Crash Pass ]
 crbug.com/591099 animations/keyframes-rule.html [ Failure ]
 crbug.com/591099 animations/lazy-detached-animation-stop.html [ Failure ]
-crbug.com/591099 animations/negative-delay-events.html [ Failure ]
-crbug.com/591099 animations/play-state-initially-paused-start-event.html [ Failure ]
+crbug.com/591099 animations/events/negative-delay-events.html [ Failure ]
+crbug.com/591099 animations/events/play-state-initially-paused-start-event.html [ Failure ]
 crbug.com/591099 animations/play-state.html [ Failure ]
 crbug.com/591099 animations/prefixed/animation-inherit-initial-unprefixed.html [ Failure ]
 crbug.com/591099 animations/prefixed/keyframes-cssom-prefixed-02.html [ Failure ]
 crbug.com/591099 animations/prefixed/keyframes-cssom-unprefixed-02.html [ Failure ]
-crbug.com/591099 animations/responsive/d-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/responsive/line-height-responsive.html [ Pass Timeout ]
+crbug.com/591099 animations/responsive/interpolation/d-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/interpolation/line-height-responsive.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
 crbug.com/591099 animations/skew-notsequential-compositor.html [ Failure ]
 crbug.com/591099 animations/stability/animation-end-event-destroy-renderer.html [ Failure ]
@@ -502,14 +502,14 @@
 crbug.com/591099 animations/svg-attribute-interpolation/svg-xChannelSelector-interpolation.html [ Crash Pass ]
 crbug.com/591099 animations/svg-attribute-interpolation/svg-y-list-interpolation.html [ Crash Pass ]
 crbug.com/591099 animations/svg-attribute-interpolation/svg-z-interpolation.html [ Crash Pass ]
-crbug.com/591099 animations/svg-attribute-responsive/svg-d-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/svg-attribute-responsive/svg-points-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/svg-attribute-responsive/svg-tableValues-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/svg-attribute-responsive/svg-transform-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/svg-attribute-responsive/svg-x-list-responsive.html [ Crash Pass ]
-crbug.com/591099 animations/svg-presentation-attribute-animation.html [ Crash Pass ]
-crbug.com/591099 animations/svg-responsive-to-timing-updates.html [ Crash Pass ]
-crbug.com/591099 animations/timing-model.html [ Pass Timeout ]
+crbug.com/591099 animations/responsive/interpolation/svg-d-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/interpolation/svg-points-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/interpolation/svg-tableValues-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/interpolation/svg-transform-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/interpolation/svg-x-list-responsive.html [ Crash Pass ]
+crbug.com/591099 animations/svg/svg-presentation-attribute-animation.html [ Crash Pass ]
+crbug.com/591099 animations/responsive/svg-responsive-to-timing-updates.html [ Crash Pass ]
+crbug.com/591099 animations/timing/timing-model.html [ Pass Timeout ]
 crbug.com/591099 battery-status/api-defined.html [ Failure ]
 crbug.com/591099 battery-status/detached-no-crash.html [ Failure ]
 crbug.com/591099 battery-status/multiple-promises-after-resolve.html [ Failure ]
@@ -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 ]
@@ -21622,23 +21625,23 @@
 crbug.com/591099 virtual/threaded/animations/3d/change-transform-in-end-event.html [ Failure Pass ]
 crbug.com/591099 virtual/threaded/animations/3d/state-at-end-event-transform.html [ Failure Pass ]
 crbug.com/591099 virtual/threaded/animations/animation-css-rule-types.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/animation-events-create.html [ Failure ]
+crbug.com/591099 virtual/threaded/animations/events/animation-events-create.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/animations-parsing.html [ Timeout ]
-crbug.com/591099 virtual/threaded/animations/animations-responsive-to-color-change.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/clear-svg-animation-effects.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/animations-responsive-to-color-change.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/svg/clear-svg-animation-effects.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/composition/background-position-composition.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/composition/caret-color-composition.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/composition/stroke-dasharray-composition.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/computed-style.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/css-animation-overrides-svg-presentation-attribute-animation.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/delay-start-event.html [ Failure ]
+crbug.com/591099 virtual/threaded/animations/svg/css-animation-overrides-svg-presentation-attribute-animation.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/events/delay-start-event.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/display-change-does-not-terminate-animation.html [ Crash Failure ]
 crbug.com/591099 virtual/threaded/animations/display-inline-style-adjust.html [ Failure Timeout ]
 crbug.com/591099 virtual/threaded/animations/display-none-cancel-computedstyle.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/display-none-terminates-animation.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/img-element-transform.html [ Crash Pass Timeout ]
 crbug.com/591099 virtual/threaded/animations/inline-block-transform.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/inline-element-animation-end-hit-test.html [ Failure ]
+crbug.com/591099 virtual/threaded/animations/hit-testing/inline-element-animation-end-hit-test.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/interpolation/backdrop-filter-interpolation.html [ Crash Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/background-color-interpolation.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/interpolation/background-image-interpolation.html [ Crash Timeout ]
@@ -21725,14 +21728,14 @@
 crbug.com/591099 virtual/threaded/animations/interpolation/webkit-transform-origin-interpolation.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/keyframes-rule.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/lazy-detached-animation-stop.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/negative-delay-events.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/play-state-initially-paused-start-event.html [ Failure ]
+crbug.com/591099 virtual/threaded/animations/events/negative-delay-events.html [ Failure ]
+crbug.com/591099 virtual/threaded/animations/events/play-state-initially-paused-start-event.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/play-state.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/prefixed/animation-inherit-initial-unprefixed.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/prefixed/keyframes-cssom-prefixed-02.html [ Failure ]
 crbug.com/591099 virtual/threaded/animations/prefixed/keyframes-cssom-unprefixed-02.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/responsive/d-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/responsive/line-height-responsive.html [ Pass Timeout ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/d-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/line-height-responsive.html [ Pass Timeout ]
 crbug.com/591099 virtual/threaded/animations/rotate-transform-equivalent.html [ Failure Timeout ]
 crbug.com/591099 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure Timeout ]
 crbug.com/591099 virtual/threaded/animations/stability/animation-end-event-destroy-renderer.html [ Failure ]
@@ -21897,14 +21900,14 @@
 crbug.com/591099 virtual/threaded/animations/svg-attribute-interpolation/svg-xChannelSelector-interpolation.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/svg-attribute-interpolation/svg-y-list-interpolation.html [ Crash Pass ]
 crbug.com/591099 virtual/threaded/animations/svg-attribute-interpolation/svg-z-interpolation.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-responsive/svg-d-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-responsive/svg-points-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-responsive/svg-tableValues-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-responsive/svg-transform-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-responsive/svg-x-list-responsive.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-presentation-attribute-animation.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/svg-responsive-to-timing-updates.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/timing-model.html [ Pass Timeout ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/svg-d-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/svg-points-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/svg-tableValues-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/svg-transform-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/interpolation/svg-x-list-responsive.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/svg/svg-presentation-attribute-animation.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/responsive/svg-responsive-to-timing-updates.html [ Crash Pass ]
+crbug.com/591099 virtual/threaded/animations/timing/timing-model.html [ Pass Timeout ]
 crbug.com/591099 virtual/threaded/compositing/visibility/compositing-and-visibility-turned-off-together.html [ Failure ]
 crbug.com/591099 virtual/threaded/compositing/visibility/hidden-iframe.html [ Failure ]
 crbug.com/591099 virtual/threaded/compositing/visibility/layer-visible-content.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 18a99ab7..b683361b 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -181,7 +181,7 @@
 Bug(none) editing/inserting/delete-insignificant-text-crash.html [ Timeout ]
 Bug(none) editing/inserting/insert-html-crash.html [ Timeout ]
 Bug(none) editing/style/apply-style-join-child-text-nodes-crash.html [ Timeout ]
-Bug(none) external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage.html [ Failure Timeout ]
+Bug(none) external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/FileAPI/blob/Blob-XHR-revoke.html [ Failure Timeout ]
 Bug(none) external/wpt/FileAPI/blob/Blob-constructor.html [ Failure Timeout ]
 Bug(none) external/wpt/FileAPI/blob/Blob-slice.html [ Failure Timeout ]
@@ -195,7 +195,7 @@
 Bug(none) external/wpt/FileAPI/reading-data-section/filereader_readAsText.html [ Failure Timeout ]
 Bug(none) external/wpt/FileAPI/reading-data-section/filereader_result.html [ Failure Timeout ]
 Bug(none) external/wpt/FileAPI/url/blob-url-in-sandboxed-iframe.html [ Failure Timeout ]
-Bug(none) external/wpt/FileAPI/url/url_xmlhttprequest.html [ Failure Timeout ]
+Bug(none) external/wpt/FileAPI/url/url_xmlhttprequest.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/IndexedDB [ Failure Timeout ]
 Bug(none) external/wpt/WebCryptoAPI/derive_bits_keys/test_ecdh_bits.https.html [ Failure Timeout ]
 Bug(none) external/wpt/WebCryptoAPI/derive_bits_keys/test_ecdh_keys.https.html [ Failure Timeout ]
@@ -249,7 +249,7 @@
 Bug(none) external/wpt/WebCryptoAPI/wrapKey_unwrapKey/test_wrapKey_unwrapKey.https.html [ Failure Timeout ]
 Bug(none) external/wpt/WebIDL/ecmascript-binding/es-exceptions/exceptions.html [ Failure Timeout ]
 Bug(none) external/wpt/WebIDL/ecmascript-binding/has-instance.html [ Failure Timeout ]
-Bug(none) external/wpt/XMLHttpRequest [ Failure Timeout ]
+Bug(none) external/wpt/XMLHttpRequest [ Crash Failure Timeout ]
 Bug(none) external/wpt/background-fetch/interfaces-worker.https.html [ Failure Timeout ]
 Bug(none) external/wpt/battery-status/battery-discharging-manual.https.html [ Failure Timeout ]
 Bug(none) external/wpt/battery-status/battery-full-manual.https.html [ Failure Timeout ]
@@ -738,14 +738,7 @@
 Bug(none) external/wpt/navigation-timing/nav2_test_attributes_values.html [ Failure Timeout ]
 Bug(none) external/wpt/navigation-timing/nav2_test_unloadEvents_previous_document_cross_origin.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/notifications/shownotification-resolve-manual.https.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/filter/offscreencanvas.filter.w.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.commit.w.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.convert.to.blob.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.convert.to.blob.w.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen.w.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.transferrable.html [ Failure Timeout ]
-Bug(none) external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.transferrable.w.html [ Failure Timeout ]
+Bug(none) external/wpt/offscreen-canvas [ Crash Failure Timeout ]
 Bug(none) external/wpt/orientation-sensor/idlharness.https.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/allowpaymentrequest/active-document-cross-origin.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/payment-request/allowpaymentrequest/active-document-same-origin.https.html [ Failure Timeout ]
@@ -1594,10 +1587,12 @@
 Bug(none) fast/canvas/OffscreenCanvas-strokeRect-in-worker.html [ Timeout ]
 Bug(none) fast/canvas/OffscreenCanvas-transform-shadow-in-worker.html [ Timeout ]
 Bug(none) fast/canvas/canvas-createImageBitmap-blob-in-workers.html [ Timeout ]
-Bug(none) fast/canvas/canvas-createImageBitmap-drawImage.html [ Failure ]
+Bug(none) fast/canvas/canvas-createImageBitmap-drawImage.html [ Crash Failure ]
 Bug(none) fast/canvas/canvas-createImageBitmap-from-canvas-toBlob.html [ Timeout ]
-Bug(none) fast/canvas/canvas-createImageBitmap-immutable.html [ Timeout ]
-Bug(none) fast/canvas/canvas-createImageBitmap-resize.html [ Failure ]
+Bug(none) fast/canvas/canvas-createImageBitmap-immutable.html [ Crash Timeout ]
+Bug(none) fast/canvas/canvas-createImageBitmap-invalid-blob-in-workers.html [ Crash ] 
+Bug(none) fast/canvas/canvas-createImageBitmap-resize.html [ Crash Failure ]
+Bug(none) fast/canvas/canvas-createImageBitmap-size-tooBig.html [ Crash ]
 Bug(none) fast/canvas/canvas-drawImage-live-video.html [ Timeout ]
 Bug(none) fast/canvas/canvas-toBlob-defaultpng.html [ Timeout ]
 Bug(none) fast/canvas/canvas-toBlob-jpeg-maximum-quality.html [ Timeout ]
@@ -1609,9 +1604,9 @@
 Bug(none) fast/canvas/webgl/offscreenCanvas-context-lost-restored-worker.html [ Timeout ]
 Bug(none) fast/canvas/webgl/offscreenCanvas-context-lost-worker.html [ Timeout ]
 Bug(none) fast/canvas/webgl/offscreenCanvas-transferToImageBitmap-texImage2D.html [ Crash Pass Timeout ]
-Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-blob-resize.html [ Failure ]
-Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-blob.html [ Failure ]
-Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-imageBitmap-from-blob.html [ Failure ]
+Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-blob-resize.html [ Crash Failure ]
+Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-blob.html [ Crash Failure ]
+Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-imageBitmap-from-blob.html [ Crash Failure ]
 Bug(none) fast/css/counters/counter-traverse-table-cell.html [ Failure ]
 Bug(none) fast/css/font-face-attribute-remove.html [ Timeout ]
 Bug(none) fast/css/object-fit-grow-landscape.html [ Failure ]
@@ -1660,7 +1655,7 @@
 Bug(none) fast/events/touch/gesture/long-press-focuses-frame.html [ Failure ]
 Bug(none) fast/events/wheel/mouse-wheel-scroll-latching.html [ Timeout Pass ]
 Bug(none) fast/files/apply-blob-url-to-img.html [ Timeout ]
-Bug(none) fast/files/apply-blob-url-to-xhr.html [ Timeout ]
+Bug(none) fast/files/apply-blob-url-to-xhr.html [ Crash Timeout ]
 Bug(none) fast/files/blob-close-read.html [ Failure ]
 Bug(none) fast/files/blob-close-revoke.html [ Failure ]
 Bug(none) fast/files/blob-constructor.html [ Timeout ]
@@ -1679,13 +1674,13 @@
 Bug(none) fast/files/read-blob-async.html [ Failure ]
 Bug(none) fast/files/read-file-async.html [ Failure ]
 Bug(none) fast/files/workers/inline-worker-via-blob-url.html [ Timeout ]
-Bug(none) fast/files/workers/worker-apply-blob-url-to-xhr.html [ Failure Timeout ]
+Bug(none) fast/files/workers/worker-apply-blob-url-to-xhr.html [ Crash Failure Timeout ]
 Bug(none) fast/files/workers/worker-read-blob-async.html [ Failure ]
 Bug(none) fast/files/workers/worker-read-blob-sync.html [ Failure ]
 Bug(none) fast/files/workers/worker-read-file-async.html [ Failure ]
 Bug(none) fast/files/workers/worker-read-file-constructor-async.html [ Timeout ]
 Bug(none) fast/files/workers/worker-read-file-sync.html [ Failure ]
-Bug(none) fast/files/xhr-response-blob.html [ Failure ]
+Bug(none) fast/files/xhr-response-blob.html [ Crash Failure ]
 Bug(none) fast/filesystem/file-writer-truncate-extend.html [ Failure ]
 Bug(none) fast/filesystem/file-writer-write-overlapped.html [ Failure ]
 Bug(none) fast/filesystem/filesystem-reference.html [ Timeout ]
@@ -2193,7 +2188,7 @@
 Bug(none) http/tests/fetch/workers/thorough/scheme-data-base-https-other-https.html [ Timeout ]
 Bug(none) http/tests/fetch/workers/thorough/scheme-data-other-https.html [ Timeout ]
 Bug(none) http/tests/fetch/workers/thorough/scheme-data.html [ Timeout ]
-Bug(none) http/tests/fileapi/blob-url-in-subframe.html [ Timeout ]
+Bug(none) http/tests/fileapi/blob-url-in-subframe.html [ Crash Timeout ]
 Bug(none) http/tests/history/post-replace-state-reload.html [ Failure ]
 Bug(none) http/tests/history/push-state-in-new-frame.html [ Timeout ]
 Bug(none) http/tests/htmlimports/import-cors-credentials.html [ Failure ]
@@ -2213,6 +2208,7 @@
 Bug(none) http/tests/inspector/extensions/multiple-extensions.html [ Timeout ]
 Bug(none) http/tests/linkHeader/link-preconnect-schemeless.https.php [ Timeout ]
 Bug(none) http/tests/loading/307-after-303-after-post.html [ Failure ]
+Bug(none) http/tests/loading/doc-write-sync-third-party-script-reload.html [ Crash ]
 Bug(none) http/tests/loading/bad-scheme-subframe.html [ Failure ]
 Bug(none) http/tests/loading/pdf-commit-load-callbacks.html [ Crash Timeout ]
 Bug(none) http/tests/loading/preload-image-sizes-2x.html [ Failure ]
@@ -2628,7 +2624,7 @@
 Bug(none) http/tests/websocket/workers/worker-reload.html [ Timeout ]
 Bug(none) http/tests/workers/shared-worker-secure-context.https.html [ Timeout ]
 Bug(none) http/tests/workers/text-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest [ Failure Timeout ]
+Bug(none) http/tests/xmlhttprequest [ Crash Failure Timeout ]
 Bug(none) imagecapture/MediaStreamTrack-applyConstraints-getSettings.html [ Timeout ]
 Bug(none) imagecapture/MediaStreamTrack-applyConstraints-reject.html [ Timeout ]
 Bug(none) imagecapture/MediaStreamTrack-applyConstraints.html [ Timeout ]
@@ -2816,11 +2812,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/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index c28216d..9a2c7a75 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1623,7 +1623,7 @@
 # transforms/transform-overflow.html
 
 # Subpixel adjustments due to differences in compositing
-crbug.com/589265 animations/animated-filter-svg-element.html [ Failure Crash ]
+crbug.com/589265 animations/svg/animated-filter-svg-element.html [ Failure Crash ]
 crbug.com/589265 compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ Failure ]
 crbug.com/589265 fast/forms/number/number-appearance-spinbutton-layer.html [ Failure ]
 crbug.com/589265 fast/layers/add-layer-with-nested-stacking.html [ Failure ]
@@ -1634,7 +1634,7 @@
 crbug.com/589265 svg/custom/root-container-opacity-clip-viewBox.svg [ Failure ]
 crbug.com/589265 svg/foreignObject/filter.html [ Failure ]
 crbug.com/589265 svg/text/text-layout-crash.html [ Failure ]
-crbug.com/589265 virtual/threaded/animations/animated-filter-svg-element.html [ Failure Crash ]
+crbug.com/589265 virtual/threaded/animations/svg/animated-filter-svg-element.html [ Failure Crash ]
 
 # Some work remains to fully support composited animation and scrolling.
 crbug.com/702350 transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 643bef0..a08b1ed1 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -165,9 +165,9 @@
 crbug.com/248938 virtual/threaded/animations/3d/change-transform-in-end-event.html [ Slow ]
 crbug.com/248938 virtual/threaded/animations/3d/state-at-end-event-transform.html [ Slow ]
 crbug.com/248938 virtual/threaded/animations/3d/transform-perspective.html [ Slow ]
-crbug.com/248938 virtual/threaded/animations/animation-direction-reverse-fill-mode-hardware.html [ Slow ]
-crbug.com/248938 virtual/threaded/animations/animation-direction-reverse-fill-mode.html [ Slow ]
-crbug.com/248938 virtual/threaded/animations/animation-direction-reverse-hardware.html [ Slow ]
+crbug.com/248938 virtual/threaded/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware.html [ Slow ]
+crbug.com/248938 virtual/threaded/animations/direction-and-fill/animation-direction-reverse-fill-mode.html [ Slow ]
+crbug.com/248938 virtual/threaded/animations/direction-and-fill/animation-direction-reverse-hardware.html [ Slow ]
 crbug.com/248938 virtual/threaded/animations/stability/animation-on-inline-crash.html [ Slow ]
 crbug.com/248938 virtual/threaded/animations/cross-fade-background-image.html [ Slow ]
 crbug.com/248938 virtual/threaded/animations/cross-fade-border-image-source.html [ Slow ]
@@ -179,10 +179,10 @@
 crbug.com/311482 virtual/threaded/animations/prefixed/keyframes-unprefixed-03.html [ Slow ]
 crbug.com/243871 virtual/threaded/fast/scroll-behavior/ [ Slow ]
 crbug.com/243871 virtual/threaded/fast/idle-callback/idle_periods.html [ Slow ]
-crbug.com/664857 virtual/threaded/animations/transform-responsive-neutral-keyframe.html [ Slow ]
-crbug.com/669911 virtual/threaded/animations/zoom-responsive-transform-animation.html [ Slow ]
+crbug.com/664857 virtual/threaded/animations/responsive/transform-responsive-neutral-keyframe.html [ Slow ]
+crbug.com/669911 virtual/threaded/animations/responsive/zoom-responsive-transform-animation.html [ Slow ]
 
-crbug.com/258896 animations/animation-direction-reverse-fill-mode.html [ Slow ]
+crbug.com/258896 animations/direction-and-fill/animation-direction-reverse-fill-mode.html [ Slow ]
 
 # This test has to generate >250MB of data which takes ~6s in both release and debug.
 crbug.com/420240 http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index cbf0890..1fb955be 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 ]
@@ -2831,6 +2831,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/animations/animation-css-rule-types.html b/third_party/WebKit/LayoutTests/animations/animation-css-rule-types.html
index b32d662..1dc95e01 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-css-rule-types.html
+++ b/third_party/WebKit/LayoutTests/animations/animation-css-rule-types.html
@@ -6,6 +6,18 @@
 <body>
 <p id="description"></p>
 <div id="console"></div>
-<script src="script-tests/animation-css-rule-types.js"></script>
+<script>
+description(
+'This test checks that the CSSRule RuleTypes for keyframe-related rules are what we expect.'
+);
+
+var ruleType = window.CSSRule.KEYFRAMES_RULE;
+shouldBe("ruleType", "7");
+ruleType = window.CSSRule.KEYFRAME_RULE;
+shouldBe("ruleType", "8");
+
+debug('If we got to this point then we did not crash and the test has passed.');
+var successfullyParsed = true;
+</script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/animations/animate-shorthand-var.html b/third_party/WebKit/LayoutTests/animations/custom-properties/animate-shorthand-var.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/animations/animate-shorthand-var.html
rename to third_party/WebKit/LayoutTests/animations/custom-properties/animate-shorthand-var.html
index 089ec3be..dacaed3 100644
--- a/third_party/WebKit/LayoutTests/animations/animate-shorthand-var.html
+++ b/third_party/WebKit/LayoutTests/animations/custom-properties/animate-shorthand-var.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
 body {
   --x: green;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-alternate-reverse.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate-reverse.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-alternate-reverse.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate-reverse.html
index 7bb7f90c..d6e9a3c 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-alternate-reverse.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate-reverse.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Test of animation-direction</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     #target {
       animation-direction: alternate-reverse;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-alternate.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-alternate.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate.html
index 2d1395b..1ded81d3 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-alternate.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-alternate.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Test of animation-direction</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     #target {
       animation-direction: alternate;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-normal.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-normal.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-normal.html
index feb0adba..ed0c888 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-normal.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Test of animation-direction</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     #target {
       animation-direction: normal;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode-hardware-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode-hardware-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode-hardware.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode-hardware.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware.html
index c800edb..675aebb8 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode-hardware.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode-hardware.html
@@ -32,7 +32,7 @@
       animation-direction: alternate-reverse;
     }
   </style>
-  <script src="resources/animation-test-helpers.js"></script>
+  <script src="../resources/animation-test-helpers.js"></script>
   <script>
     const numAnims = 1;
     var animsFinished = 0;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode.html
index 0315de73..ba1cdfe 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-fill-mode.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-fill-mode.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Test of animation-direction</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     .box {
       animation-delay: 1s;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-opacity-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-opacity-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-opacity-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-opacity-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-opacity.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-opacity.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-opacity.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-opacity.html
index fb6190a..a024c59 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware-opacity.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware-opacity.html
@@ -58,7 +58,7 @@
       100% { opacity: 1.0; }
     }
   </style>
-  <script src="resources/animation-test-helpers.js"></script>
+  <script src="../resources/animation-test-helpers.js"></script>
   <script>
     const expectedValues = [
       // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware.html
index 75b20fb5..70ffbf3e 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-hardware.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-hardware.html
@@ -58,7 +58,7 @@
       100% { transform: translateX(200px); }
     }
   </style>
-  <script src="resources/animation-test-helpers.js"></script>
+  <script src="../resources/animation-test-helpers.js"></script>
   <script>
     const expectedValues = [
       // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-non-hardware.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-non-hardware.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-non-hardware.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-non-hardware.html
index 4fa429f..bbf1ecc 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-non-hardware.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-non-hardware.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     .box {
       animation-duration: 2s;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions-hardware-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions-hardware-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions-hardware-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions-hardware-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions-hardware.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions-hardware.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions-hardware.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions-hardware.html
index 8a98010b..3a4277b9 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions-hardware.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions-hardware.html
@@ -46,7 +46,7 @@
       to { transform: translateX(200px); }
     }
   </style>
-  <script src="resources/animation-test-helpers.js"></script>
+  <script src="../resources/animation-test-helpers.js"></script>
   <script>
     const expectedValues = [
       // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions.html
index a6808bc..18114a0 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-direction-reverse-timing-functions.html
+++ b/third_party/WebKit/LayoutTests/animations/direction-and-fill/animation-direction-reverse-timing-functions.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Test of animation-direction timing functions</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
     .box {
       animation-duration: 2s;
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-forwards2-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-forwards2-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-forwards2-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-forwards2-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-forwards2.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-forwards2.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-forwards2.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-forwards2.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-iteration-count-non-integer-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-iteration-count-non-integer-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-iteration-count-non-integer.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-iteration-count-non-integer.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-iteration-count-non-integer.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-iteration-count-non-integer.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-missing-from-to-keyframes-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-missing-from-to-keyframes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-missing-from-to-keyframes-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-missing-from-to-keyframes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-missing-from-to-keyframes.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-missing-from-to-keyframes.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-multiple-keyframes-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-multiple-keyframes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-multiple-keyframes-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-multiple-keyframes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-multiple-keyframes.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-multiple-keyframes.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-multiple-keyframes.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-multiple-keyframes.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-removed-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-removed-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-removed-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-removed-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-removed.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-removed.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-removed.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-removed.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-transform-expected.txt b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-transform-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-transform-expected.txt
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-transform-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode-transform.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-transform.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode-transform.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode-transform.html
diff --git a/third_party/WebKit/LayoutTests/animations/fill-mode.html b/third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/fill-mode.html
rename to third_party/WebKit/LayoutTests/animations/direction-and-fill/fill-mode.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-end-event-short-iterations-expected.txt b/third_party/WebKit/LayoutTests/animations/events/animation-end-event-short-iterations-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-end-event-short-iterations-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/animation-end-event-short-iterations-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-end-event-short-iterations.html b/third_party/WebKit/LayoutTests/animations/events/animation-end-event-short-iterations.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-end-event-short-iterations.html
rename to third_party/WebKit/LayoutTests/animations/events/animation-end-event-short-iterations.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-events-create-expected.txt b/third_party/WebKit/LayoutTests/animations/events/animation-events-create-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-events-create-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/animation-events-create-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-events-create.html b/third_party/WebKit/LayoutTests/animations/events/animation-events-create.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/animations/animation-events-create.html
rename to third_party/WebKit/LayoutTests/animations/events/animation-events-create.html
index f65a16d..b94f7e5 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-events-create.html
+++ b/third_party/WebKit/LayoutTests/animations/events/animation-events-create.html
@@ -1,6 +1,6 @@
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
+<script src="../../resources/js-test.js"></script>
 </head>
 <body>
 <p id="description"></p>
diff --git a/third_party/WebKit/LayoutTests/animations/animation-immediate-start-event-after-ondemand-update-expected.txt b/third_party/WebKit/LayoutTests/animations/events/animation-immediate-start-event-after-ondemand-update-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-immediate-start-event-after-ondemand-update-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/animation-immediate-start-event-after-ondemand-update-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-immediate-start-event-after-ondemand-update.html b/third_party/WebKit/LayoutTests/animations/events/animation-immediate-start-event-after-ondemand-update.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-immediate-start-event-after-ondemand-update.html
rename to third_party/WebKit/LayoutTests/animations/events/animation-immediate-start-event-after-ondemand-update.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-iteration-event-short-iterations-expected.txt b/third_party/WebKit/LayoutTests/animations/events/animation-iteration-event-short-iterations-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-iteration-event-short-iterations-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/animation-iteration-event-short-iterations-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-iteration-event-short-iterations.html b/third_party/WebKit/LayoutTests/animations/events/animation-iteration-event-short-iterations.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-iteration-event-short-iterations.html
rename to third_party/WebKit/LayoutTests/animations/events/animation-iteration-event-short-iterations.html
diff --git a/third_party/WebKit/LayoutTests/animations/compositor-start-event-timing.html b/third_party/WebKit/LayoutTests/animations/events/compositor-start-event-timing.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/animations/compositor-start-event-timing.html
rename to third_party/WebKit/LayoutTests/animations/events/compositor-start-event-timing.html
index e12b8b7..f02449e 100644
--- a/third_party/WebKit/LayoutTests/animations/compositor-start-event-timing.html
+++ b/third_party/WebKit/LayoutTests/animations/events/compositor-start-event-timing.html
@@ -1,6 +1,6 @@
 <!doctype html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
 .start {
     animation: anim 1ms;
diff --git a/third_party/WebKit/LayoutTests/animations/delay-start-event-expected.txt b/third_party/WebKit/LayoutTests/animations/events/delay-start-event-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/delay-start-event-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/delay-start-event-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/delay-start-event.html b/third_party/WebKit/LayoutTests/animations/events/delay-start-event.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/delay-start-event.html
rename to third_party/WebKit/LayoutTests/animations/events/delay-start-event.html
diff --git a/third_party/WebKit/LayoutTests/animations/empty-keyframe-triggers.event.html b/third_party/WebKit/LayoutTests/animations/events/empty-keyframe-triggers.event.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/animations/empty-keyframe-triggers.event.html
rename to third_party/WebKit/LayoutTests/animations/events/empty-keyframe-triggers.event.html
index 3ee42e7e..a0b50ba 100644
--- a/third_party/WebKit/LayoutTests/animations/empty-keyframe-triggers.event.html
+++ b/third_party/WebKit/LayoutTests/animations/events/empty-keyframe-triggers.event.html
@@ -1,6 +1,6 @@
 <!doctype html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim { }
   #target { animation: anim; }
diff --git a/third_party/WebKit/LayoutTests/animations/events-with-short-duration-and-delay-expected.txt b/third_party/WebKit/LayoutTests/animations/events/events-with-short-duration-and-delay-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/events-with-short-duration-and-delay-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/events-with-short-duration-and-delay-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/events-with-short-duration-and-delay.html b/third_party/WebKit/LayoutTests/animations/events/events-with-short-duration-and-delay.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/events-with-short-duration-and-delay.html
rename to third_party/WebKit/LayoutTests/animations/events/events-with-short-duration-and-delay.html
diff --git a/third_party/WebKit/LayoutTests/animations/finish-event-after-gc.html b/third_party/WebKit/LayoutTests/animations/events/finish-event-after-gc.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/animations/finish-event-after-gc.html
rename to third_party/WebKit/LayoutTests/animations/events/finish-event-after-gc.html
index 7cba44fb..8962486 100644
--- a/third_party/WebKit/LayoutTests/animations/finish-event-after-gc.html
+++ b/third_party/WebKit/LayoutTests/animations/events/finish-event-after-gc.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
 <script>
 var layoutTest = async_test('Finish event should be delivered even if a GC occurs. This test passes if it does not time out.');
diff --git a/third_party/WebKit/LayoutTests/animations/negative-delay-events-expected.txt b/third_party/WebKit/LayoutTests/animations/events/negative-delay-events-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/negative-delay-events-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/negative-delay-events-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/negative-delay-events.html b/third_party/WebKit/LayoutTests/animations/events/negative-delay-events.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/negative-delay-events.html
rename to third_party/WebKit/LayoutTests/animations/events/negative-delay-events.html
diff --git a/third_party/WebKit/LayoutTests/animations/play-state-initially-paused-start-event-expected.txt b/third_party/WebKit/LayoutTests/animations/events/play-state-initially-paused-start-event-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/play-state-initially-paused-start-event-expected.txt
rename to third_party/WebKit/LayoutTests/animations/events/play-state-initially-paused-start-event-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/play-state-initially-paused-start-event.html b/third_party/WebKit/LayoutTests/animations/events/play-state-initially-paused-start-event.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/play-state-initially-paused-start-event.html
rename to third_party/WebKit/LayoutTests/animations/events/play-state-initially-paused-start-event.html
diff --git a/third_party/WebKit/LayoutTests/animations/font-size-using-ems.html-disabled b/third_party/WebKit/LayoutTests/animations/font-size-using-ems.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/font-size-using-ems.html-disabled
rename to third_party/WebKit/LayoutTests/animations/font-size-using-ems.html
diff --git a/third_party/WebKit/LayoutTests/animations/get-css-players.html b/third_party/WebKit/LayoutTests/animations/getAnimations-css.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/get-css-players.html
rename to third_party/WebKit/LayoutTests/animations/getAnimations-css.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-hit-test-expected.txt b/third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-hit-test-expected.txt
rename to third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-hit-test-transform-expected.txt b/third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-transform-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-hit-test-transform-expected.txt
rename to third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-transform-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/animation-hit-test-transform.html b/third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-transform.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-hit-test-transform.html
rename to third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test-transform.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-hit-test.html b/third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-hit-test.html
rename to third_party/WebKit/LayoutTests/animations/hit-testing/animation-hit-test.html
diff --git a/third_party/WebKit/LayoutTests/animations/composited-with-hit-testing-expected.html b/third_party/WebKit/LayoutTests/animations/hit-testing/composited-with-hit-testing-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/composited-with-hit-testing-expected.html
rename to third_party/WebKit/LayoutTests/animations/hit-testing/composited-with-hit-testing-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/composited-with-hit-testing.html b/third_party/WebKit/LayoutTests/animations/hit-testing/composited-with-hit-testing.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/composited-with-hit-testing.html
rename to third_party/WebKit/LayoutTests/animations/hit-testing/composited-with-hit-testing.html
diff --git a/third_party/WebKit/LayoutTests/animations/inline-element-animation-end-hit-test-expected.txt b/third_party/WebKit/LayoutTests/animations/hit-testing/inline-element-animation-end-hit-test-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/inline-element-animation-end-hit-test-expected.txt
rename to third_party/WebKit/LayoutTests/animations/hit-testing/inline-element-animation-end-hit-test-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/inline-element-animation-end-hit-test.html b/third_party/WebKit/LayoutTests/animations/hit-testing/inline-element-animation-end-hit-test.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/inline-element-animation-end-hit-test.html
rename to third_party/WebKit/LayoutTests/animations/hit-testing/inline-element-animation-end-hit-test.html
index 52465118..d9e13c02 100644
--- a/third_party/WebKit/LayoutTests/animations/inline-element-animation-end-hit-test.html
+++ b/third_party/WebKit/LayoutTests/animations/hit-testing/inline-element-animation-end-hit-test.html
@@ -16,7 +16,7 @@
 }
 
 </style>
-<script src="../resources/js-test.js"></script>
+<script src="../../resources/js-test.js"></script>
 <div class="margin">
   <span class="grow">
     <div id="box"></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-assorted-lengths.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-assorted-lengths.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-assorted-lengths.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-assorted-lengths.html
index 68a0bccd..e0560c7 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-assorted-lengths.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-assorted-lengths.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundPosition.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundPosition.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundPosition.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundPosition.html
index d9b46bdd..5fd5212 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundPosition.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundPosition.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundSize.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundSize.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundSize.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundSize.html
index 59557d7..8b84152 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-backgroundSize.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-backgroundSize.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderImageWidth.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderImageWidth.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-borderImageWidth.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderImageWidth.html
index d3f2251c..911c0b4 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderImageWidth.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderImageWidth.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderRadius.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderRadius.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-borderRadius.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderRadius.html
index 696d18a..bfd3c48c 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderRadius.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderRadius.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='element'></div>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderWidth.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderWidth.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-borderWidth.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderWidth.html
index 9972665..8c9ef22 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-borderWidth.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-borderWidth.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-boxShadow.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-boxShadow.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-boxShadow.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-boxShadow.html
index 32c3f8f..f2160c86 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-boxShadow.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-boxShadow.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-fontSize.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontSize.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-fontSize.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontSize.html
index 9f794fd..d3e0426 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-fontSize.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontSize.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-fontWeight.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontWeight.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-fontWeight.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontWeight.html
index 1e8b02c..cfa61cdf 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-fontWeight.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-fontWeight.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-minHeight.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-minHeight.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-minHeight.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-minHeight.html
index eb9f669..a7a4b74 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-minHeight.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-minHeight.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-offsetDistance.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-offsetDistance.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-offsetDistance.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-offsetDistance.html
index 41ada78..7b97c5264 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-offsetDistance.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-offsetDistance.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='element'></div>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-opacity.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-opacity.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-opacity.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-opacity.html
index 24fcad5..4098150 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-opacity.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-opacity.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-perspective.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-perspective.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-perspective.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-perspective.html
index 3153ebc..7b79f49 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-perspective.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-perspective.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-shapeMargin.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-shapeMargin.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
index c188086..1b160b26 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-shapeMargin.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-shapeMargin.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-strokeDasharray.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-strokeDasharray.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-strokeDasharray.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-strokeDasharray.html
index d088ad09..621fcd5 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-strokeDasharray.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-strokeDasharray.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-textIndent.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-textIndent.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-textIndent.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-textIndent.html
index eca4d1d..d3c4bc9b 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-textIndent.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-textIndent.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id='container'>
     <div id='element'></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-color-change.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-color-change.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-to-color-change.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-color-change.html
index f0840bf..959581b 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-color-change.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-color-change.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
 a { visibility: hidden; }
 </style>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-inherited-change.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-inherited-change.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-to-inherited-change.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-inherited-change.html
index 08d1042..67433b8f 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-inherited-change.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-inherited-change.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
     <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-style-change.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-to-style-change.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
index c337ebe..825cf642 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-to-style-change.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-to-style-change.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-transform.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-transform.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-transform.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-transform.html
index 940b756d..ffaa8f26 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-transform.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-transform.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-translate.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-translate.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-translate.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-translate.html
index 1e4a7eb..e45f0a3 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-translate.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-translate.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/animations-responsive-verticalAlign.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-verticalAlign.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/animations/animations-responsive-verticalAlign.html
rename to third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-verticalAlign.html
index 8521d93..a97c401 100644
--- a/third_party/WebKit/LayoutTests/animations/animations-responsive-verticalAlign.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-verticalAlign.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id='container'>
 <div id='element'></div>
diff --git a/third_party/WebKit/LayoutTests/animations/filter-responsive-neutral-keyframe-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/filter-responsive-neutral-keyframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/filter-responsive-neutral-keyframe-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/filter-responsive-neutral-keyframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/filter-responsive-neutral-keyframe.html b/third_party/WebKit/LayoutTests/animations/responsive/filter-responsive-neutral-keyframe.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/filter-responsive-neutral-keyframe.html
rename to third_party/WebKit/LayoutTests/animations/responsive/filter-responsive-neutral-keyframe.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/backdrop-filter-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/backdrop-filter-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/backdrop-filter-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/backdrop-filter-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/background-image-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/background-image-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/background-image-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/background-image-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/background-position-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/background-position-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/background-position-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/background-position-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/border-image-outset-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-outset-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/border-image-outset-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-outset-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/border-image-slice-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-slice-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/border-image-slice-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-slice-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/border-image-source-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-source-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/border-image-source-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/border-image-source-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/box-shadow-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/box-shadow-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/box-shadow-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/box-shadow-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/clip-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/clip-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/clip-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/clip-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/color-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/color-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/d-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/d-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/d-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/d-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/fill-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/fill-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/fill-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/fill-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/font-size-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-size-responsive.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/responsive/font-size-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-size-responsive.html
index f3f8aab..314e655 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/font-size-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-size-responsive.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
 <div id="container">
   <div id="target"></div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/font-variation-settings-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-variation-settings-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/font-variation-settings-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-variation-settings-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/font-weight-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-weight-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/font-weight-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/font-weight-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/left-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/left-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/left-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/left-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/line-height-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/line-height-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/line-height-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/line-height-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/offset-rotate-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/offset-rotate-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/offset-rotate-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/offset-rotate-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/resources/responsive-test.js
similarity index 98%
rename from third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/resources/responsive-test.js
index 2c47f631..118268b 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/resources/responsive-test.js
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/resources/responsive-test.js
@@ -281,8 +281,8 @@
   });
 }
 
-loadScript('../../resources/testharness.js').then(() => {
-  return loadScript('../../resources/testharnessreport.js');
+loadScript('../../../resources/testharness.js').then(() => {
+  return loadScript('../../../resources/testharnessreport.js');
 }).then(() => {
   var asyncHandle = async_test('This test uses responsive-test.js.')
   runPendingResponsiveTests().then(() => {
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/rotate-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/rotate-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/rotate-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/scale-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/scale-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/scale-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/scale-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/shape-outside-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/shape-outside-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/shape-outside-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/shape-outside-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/stroke-dasharray-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/stroke-dasharray-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-d-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-d-responsive.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-d-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-d-responsive.html
index 2a3fd41..57bdbc70 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-d-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-d-responsive.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../responsive/resources/responsive-test.js"></script>
+<script src="resources/responsive-test.js"></script>
 <script>
 assertSVGResponsive({
   targetTag: 'path',
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-points-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-points-responsive.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-points-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-points-responsive.html
index 9d75db82..7ba3a7cf 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-points-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-points-responsive.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../responsive/resources/responsive-test.js"></script>
+<script src="resources/responsive-test.js"></script>
 <script>
 assertSVGResponsive({
   targetTag: 'polygon',
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-tableValues-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-tableValues-responsive.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-tableValues-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-tableValues-responsive.html
index 7d217d62..7146b90 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-tableValues-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-tableValues-responsive.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../responsive/resources/responsive-test.js"></script>
+<script src="resources/responsive-test.js"></script>
 <script>
 assertSVGResponsive({
   targetTag: 'feFuncG',
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-transform-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-transform-responsive.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-transform-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-transform-responsive.html
index 7f83fa4..39a7847 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-transform-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-transform-responsive.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../responsive/resources/responsive-test.js"></script>
+<script src="resources/responsive-test.js"></script>
 <script>
 function serializeSVGTransformList(transformList) {
   var elements = [];
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-x-list-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-x-list-responsive.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-x-list-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-x-list-responsive.html
index b5fa27c..a9b10be5 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-responsive/svg-x-list-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/svg-x-list-responsive.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../responsive/resources/responsive-test.js"></script>
+<script src="resources/responsive-test.js"></script>
 <script>
 assertSVGResponsive({
   targetTag: 'text',
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/text-indent-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/text-indent-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/text-indent-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/text-indent-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/transform-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/transform-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/transform-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/translate-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/translate-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/translate-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/translate-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/visibility-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/interpolation/visibility-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive/visibility-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/interpolation/visibility-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/opacity-responsive-neutral-keyframe-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/opacity-responsive-neutral-keyframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/opacity-responsive-neutral-keyframe-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/opacity-responsive-neutral-keyframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/opacity-responsive-neutral-keyframe.html b/third_party/WebKit/LayoutTests/animations/responsive/opacity-responsive-neutral-keyframe.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/opacity-responsive-neutral-keyframe.html
rename to third_party/WebKit/LayoutTests/animations/responsive/opacity-responsive-neutral-keyframe.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframe-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframe-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframe.html b/third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframe.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframe.html
rename to third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframe.html
diff --git a/third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframes.html b/third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframes.html
similarity index 96%
rename from third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframes.html
rename to third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframes.html
index 61d9911..14dda0e 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive-neutral-keyframes.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/responsive-neutral-keyframes.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim-missing-from { to { width: 200px; height: 200px; } }
   @keyframes anim-missing-to { from { left: 100px; } }
diff --git a/third_party/WebKit/LayoutTests/animations/stacked-visibility-animations-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/stacked-visibility-animations-responsive.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/animations/stacked-visibility-animations-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/stacked-visibility-animations-responsive.html
index 6489018..9f26cef 100644
--- a/third_party/WebKit/LayoutTests/animations/stacked-visibility-animations-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/stacked-visibility-animations-responsive.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id="target"></div>
 <script>
 test(() => {
diff --git a/third_party/WebKit/LayoutTests/animations/svg-responsive-to-timing-updates.html b/third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-timing-updates.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/animations/svg-responsive-to-timing-updates.html
rename to third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-timing-updates.html
index 2a684e0..a649bce 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-responsive-to-timing-updates.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-timing-updates.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <svg>
   <stop id="target" offset="0"/>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/animations/svg-responsive-to-updated-baseval.html b/third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-updated-baseval.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/animations/svg-responsive-to-updated-baseval.html
rename to third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-updated-baseval.html
index e0819e1..ec3de93 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-responsive-to-updated-baseval.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/svg-responsive-to-updated-baseval.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>SVG Web Animations should be responsive to changes in the underlying value</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
 // offset has a primitive animVal type.
 function createOffsetTestTarget() {
diff --git a/third_party/WebKit/LayoutTests/animations/transform-responsive-neutral-keyframe-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive-neutral-keyframe-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/transform-responsive-neutral-keyframe-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/transform-responsive-neutral-keyframe-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/transform-responsive-neutral-keyframe.html b/third_party/WebKit/LayoutTests/animations/responsive/transform-responsive-neutral-keyframe.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/transform-responsive-neutral-keyframe.html
rename to third_party/WebKit/LayoutTests/animations/responsive/transform-responsive-neutral-keyframe.html
diff --git a/third_party/WebKit/LayoutTests/animations/viewport-unit-animation-responsive-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/viewport-unit-animation-responsive-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/viewport-unit-animation-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/viewport-unit-animation-responsive.html
rename to third_party/WebKit/LayoutTests/animations/responsive/viewport-unit-animation-responsive.html
diff --git a/third_party/WebKit/LayoutTests/animations/zoom-responsive-transform-animation-expected.html b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-transform-animation-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/zoom-responsive-transform-animation-expected.html
rename to third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-transform-animation-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/zoom-responsive-transform-animation.html b/third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-transform-animation.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/zoom-responsive-transform-animation.html
rename to third_party/WebKit/LayoutTests/animations/responsive/zoom-responsive-transform-animation.html
diff --git a/third_party/WebKit/LayoutTests/animations/script-tests/TEMPLATE.html b/third_party/WebKit/LayoutTests/animations/script-tests/TEMPLATE.html
deleted file mode 100644
index dc90070..0000000
--- a/third_party/WebKit/LayoutTests/animations/script-tests/TEMPLATE.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="YOUR_JS_FILE_HERE"></script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/animations/script-tests/animation-css-rule-types.js b/third_party/WebKit/LayoutTests/animations/script-tests/animation-css-rule-types.js
deleted file mode 100644
index 2d76dee..0000000
--- a/third_party/WebKit/LayoutTests/animations/script-tests/animation-css-rule-types.js
+++ /dev/null
@@ -1,11 +0,0 @@
-description(
-'This test checks that the CSSRule RuleTypes for keyframe-related rules are what we expect.'
-);
-
-var ruleType = window.CSSRule.KEYFRAMES_RULE;
-shouldBe("ruleType", "7");
-ruleType = window.CSSRule.KEYFRAME_RULE;
-shouldBe("ruleType", "8");
-
-debug('If we got to this point then we did not crash and the test has passed.');
-var successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/animations/animated-filter-svg-element-expected.html b/third_party/WebKit/LayoutTests/animations/svg/animated-filter-svg-element-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animated-filter-svg-element-expected.html
rename to third_party/WebKit/LayoutTests/animations/svg/animated-filter-svg-element-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/animated-filter-svg-element.html b/third_party/WebKit/LayoutTests/animations/svg/animated-filter-svg-element.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animated-filter-svg-element.html
rename to third_party/WebKit/LayoutTests/animations/svg/animated-filter-svg-element.html
diff --git a/third_party/WebKit/LayoutTests/animations/clear-svg-animation-effects.html b/third_party/WebKit/LayoutTests/animations/svg/clear-svg-animation-effects.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/animations/clear-svg-animation-effects.html
rename to third_party/WebKit/LayoutTests/animations/svg/clear-svg-animation-effects.html
index 8b75bdc..d225a2a 100644
--- a/third_party/WebKit/LayoutTests/animations/clear-svg-animation-effects.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/clear-svg-animation-effects.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <svg>
   <stop id="target" offset="1"/>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/animations/css-animation-affects-use-elements-expected.html b/third_party/WebKit/LayoutTests/animations/svg/css-animation-affects-use-elements-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/css-animation-affects-use-elements-expected.html
rename to third_party/WebKit/LayoutTests/animations/svg/css-animation-affects-use-elements-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/css-animation-affects-use-elements.html b/third_party/WebKit/LayoutTests/animations/svg/css-animation-affects-use-elements.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/animations/css-animation-affects-use-elements.html
rename to third_party/WebKit/LayoutTests/animations/svg/css-animation-affects-use-elements.html
index ca8bbc74..b9c2c98 100644
--- a/third_party/WebKit/LayoutTests/animations/css-animation-affects-use-elements.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/css-animation-affects-use-elements.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../resources/run-after-layout-and-paint.js"></script>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
 <svg>
   <defs>
     <rect x="0" y="0" width="100" height="40" id="target" fill="green" />
diff --git a/third_party/WebKit/LayoutTests/animations/css-animation-overrides-svg-presentation-attribute-animation.html b/third_party/WebKit/LayoutTests/animations/svg/css-animation-overrides-svg-presentation-attribute-animation.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/animations/css-animation-overrides-svg-presentation-attribute-animation.html
rename to third_party/WebKit/LayoutTests/animations/svg/css-animation-overrides-svg-presentation-attribute-animation.html
index cd67cbed..e59f41a 100644
--- a/third_party/WebKit/LayoutTests/animations/css-animation-overrides-svg-presentation-attribute-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/css-animation-overrides-svg-presentation-attribute-animation.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <svg>
   <rect id="target"/>
diff --git a/third_party/WebKit/LayoutTests/animations/css-composite-animation-affects-use-elements-expected.html b/third_party/WebKit/LayoutTests/animations/svg/css-composite-animation-affects-use-elements-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/css-composite-animation-affects-use-elements-expected.html
rename to third_party/WebKit/LayoutTests/animations/svg/css-composite-animation-affects-use-elements-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/css-composite-animation-affects-use-elements.html b/third_party/WebKit/LayoutTests/animations/svg/css-composite-animation-affects-use-elements.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/css-composite-animation-affects-use-elements.html
rename to third_party/WebKit/LayoutTests/animations/svg/css-composite-animation-affects-use-elements.html
index 1a91d9f5..514bc107 100644
--- a/third_party/WebKit/LayoutTests/animations/css-composite-animation-affects-use-elements.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/css-composite-animation-affects-use-elements.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<script src="../resources/run-after-layout-and-paint.js"></script>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
 <svg>
   <defs>
     <rect x="0" y="0" width="100" height="40" id="target" fill="green" />
diff --git a/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements-expected.html b/third_party/WebKit/LayoutTests/animations/svg/svg-animation-affects-use-elements-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements-expected.html
rename to third_party/WebKit/LayoutTests/animations/svg/svg-animation-affects-use-elements-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements.html b/third_party/WebKit/LayoutTests/animations/svg/svg-animation-affects-use-elements.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/svg-animation-affects-use-elements.html
rename to third_party/WebKit/LayoutTests/animations/svg/svg-animation-affects-use-elements.html
diff --git a/third_party/WebKit/LayoutTests/animations/svg-composition-ignores-css-composition-flag.html b/third_party/WebKit/LayoutTests/animations/svg/svg-composition-ignores-css-composition-flag.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/svg-composition-ignores-css-composition-flag.html
rename to third_party/WebKit/LayoutTests/animations/svg/svg-composition-ignores-css-composition-flag.html
index d006c86b..f4cd57e9 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-composition-ignores-css-composition-flag.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/svg-composition-ignores-css-composition-flag.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <div id="cssTarget"></div>
 <svg>
diff --git a/third_party/WebKit/LayoutTests/animations/svg-presentation-attribute-animation.html b/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/animations/svg-presentation-attribute-animation.html
rename to third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
index 5fb9f4c2..320d0140 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-presentation-attribute-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/svg/svg-presentation-attribute-animation.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <svg>
   <rect id="target"/>
diff --git a/third_party/WebKit/LayoutTests/animations/text-decoration-expected.html b/third_party/WebKit/LayoutTests/animations/svg/text-decoration-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/text-decoration-expected.html
rename to third_party/WebKit/LayoutTests/animations/svg/text-decoration-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/text-decoration.html b/third_party/WebKit/LayoutTests/animations/svg/text-decoration.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/text-decoration.html
rename to third_party/WebKit/LayoutTests/animations/svg/text-decoration.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-duration-infinite-expected.html b/third_party/WebKit/LayoutTests/animations/timing/animation-duration-infinite-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-duration-infinite-expected.html
rename to third_party/WebKit/LayoutTests/animations/timing/animation-duration-infinite-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/animation-duration-infinite.html b/third_party/WebKit/LayoutTests/animations/timing/animation-duration-infinite.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/animation-duration-infinite.html
rename to third_party/WebKit/LayoutTests/animations/timing/animation-duration-infinite.html
diff --git a/third_party/WebKit/LayoutTests/animations/delay-timer-cancel-bug.html b/third_party/WebKit/LayoutTests/animations/timing/delay-timer-cancel-bug.html
similarity index 78%
rename from third_party/WebKit/LayoutTests/animations/delay-timer-cancel-bug.html
rename to third_party/WebKit/LayoutTests/animations/timing/delay-timer-cancel-bug.html
index 43d6c44..8980954 100644
--- a/third_party/WebKit/LayoutTests/animations/delay-timer-cancel-bug.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/delay-timer-cancel-bug.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id="target"></div>
 <script>
 var asyncHandle = async_test('Delayed animations are unaffected by on demand timeline updates.');
diff --git a/third_party/WebKit/LayoutTests/animations/implicit-keyframe-with-timing-function.html b/third_party/WebKit/LayoutTests/animations/timing/implicit-keyframe-with-timing-function.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/animations/implicit-keyframe-with-timing-function.html
rename to third_party/WebKit/LayoutTests/animations/timing/implicit-keyframe-with-timing-function.html
index c5396e2..7916ce8b 100644
--- a/third_party/WebKit/LayoutTests/animations/implicit-keyframe-with-timing-function.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/implicit-keyframe-with-timing-function.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id="target">Test target</div>
 <script>
 var target = document.getElementById('target');
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-multiple-timing-functions-transform-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-multiple-timing-functions-transform-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-multiple-timing-functions-transform-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-multiple-timing-functions-transform-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-multiple-timing-functions-transform.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-multiple-timing-functions-transform.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/keyframe-multiple-timing-functions-transform.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-multiple-timing-functions-transform.html
index 9f7472eb..586eae1 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-multiple-timing-functions-transform.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-multiple-timing-functions-transform.html
@@ -24,7 +24,7 @@
             to { opacity: 0.0; }
         }
     </style>
-    <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+    <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
     <script type="text/javascript" charset="utf-8">
         const expectedValues = [
           // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-multiple-animations-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-multiple-animations-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-multiple-animations-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-multiple-animations-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-multiple-animations.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-multiple-animations.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-multiple-animations.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-multiple-animations.html
index 1d3f82cb..5e2907b3 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-multiple-animations.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-multiple-animations.html
@@ -30,7 +30,7 @@
         }
     }
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
     
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-transform-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-transform-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-transform-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-transform-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-transform.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-transform.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-transform.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-transform.html
index 943e24e..9934c92 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions-transform.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions-transform.html
@@ -39,7 +39,7 @@
     }
     
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
 
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions.html
index 7e85d318..10eb189 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions.html
@@ -34,7 +34,7 @@
     }
     
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
 
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions2-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions2-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions2-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions2-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions2.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions2.html
similarity index 91%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions2.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions2.html
index b1c0e8b..126c9e78 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions2.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions2.html
@@ -38,7 +38,7 @@
       }
     }
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
 
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions3-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions3-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions3-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions3-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions3.html b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions3.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/keyframe-timing-functions3.html
rename to third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions3.html
index 316261e8..4971c27 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-timing-functions3.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/keyframe-timing-functions3.html
@@ -33,7 +33,7 @@
   100% { left: 400px; }
 }
 </style>
-<script src="resources/animation-test-helpers.js"></script>
+<script src="../resources/animation-test-helpers.js"></script>
 <script>
   const expectedValues = [
     // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/longhand-timing-function-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/longhand-timing-function-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/longhand-timing-function-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/longhand-timing-function-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/longhand-timing-function.html b/third_party/WebKit/LayoutTests/animations/timing/longhand-timing-function.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/longhand-timing-function.html
rename to third_party/WebKit/LayoutTests/animations/timing/longhand-timing-function.html
index e8ebce2..8f177f5 100644
--- a/third_party/WebKit/LayoutTests/animations/longhand-timing-function.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/longhand-timing-function.html
@@ -24,7 +24,7 @@
             to   { left: 400px; }
         }
     </style>
-    <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+    <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
     <script type="text/javascript" charset="utf-8">
         if (window.testRunner)
             testRunner.waitUntilDone();
diff --git a/third_party/WebKit/LayoutTests/animations/missing-keyframe-properties-timing-function-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/missing-keyframe-properties-timing-function-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/missing-keyframe-properties-timing-function-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/missing-keyframe-properties-timing-function-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/missing-keyframe-properties-timing-function.html b/third_party/WebKit/LayoutTests/animations/timing/missing-keyframe-properties-timing-function.html
similarity index 93%
rename from third_party/WebKit/LayoutTests/animations/missing-keyframe-properties-timing-function.html
rename to third_party/WebKit/LayoutTests/animations/timing/missing-keyframe-properties-timing-function.html
index 39fbb8b..1c56e3f 100644
--- a/third_party/WebKit/LayoutTests/animations/missing-keyframe-properties-timing-function.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/missing-keyframe-properties-timing-function.html
@@ -54,7 +54,7 @@
     }
 
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
     
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/multiple-animations-timing-function-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/multiple-animations-timing-function-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/multiple-animations-timing-function-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/multiple-animations-timing-function-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/multiple-animations-timing-function.html b/third_party/WebKit/LayoutTests/animations/timing/multiple-animations-timing-function.html
similarity index 90%
rename from third_party/WebKit/LayoutTests/animations/multiple-animations-timing-function.html
rename to third_party/WebKit/LayoutTests/animations/timing/multiple-animations-timing-function.html
index 3361bbb..9155b6c 100644
--- a/third_party/WebKit/LayoutTests/animations/multiple-animations-timing-function.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/multiple-animations-timing-function.html
@@ -22,7 +22,7 @@
             to   { top: 200px; }
         }
     </style>
-    <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+    <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
     <script type="text/javascript" charset="utf-8">
         const expectedValues = [
           // [time, element-id, property, expected-value, tolerance]
diff --git a/third_party/WebKit/LayoutTests/animations/timing-functions-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/timing-functions-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/timing-functions-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/timing-functions-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/timing-functions-neutral-keyframe.html b/third_party/WebKit/LayoutTests/animations/timing/timing-functions-neutral-keyframe.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/animations/timing-functions-neutral-keyframe.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-functions-neutral-keyframe.html
index a071e47..2122778 100644
--- a/third_party/WebKit/LayoutTests/animations/timing-functions-neutral-keyframe.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/timing-functions-neutral-keyframe.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim {
     from { animation-timing-function: linear; }
diff --git a/third_party/WebKit/LayoutTests/animations/timing-functions-update-animation.html b/third_party/WebKit/LayoutTests/animations/timing/timing-functions-update-animation.html
similarity index 94%
rename from third_party/WebKit/LayoutTests/animations/timing-functions-update-animation.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-functions-update-animation.html
index ca045ca..c72540b 100644
--- a/third_party/WebKit/LayoutTests/animations/timing-functions-update-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/timing-functions-update-animation.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim {
     from { left: 0px; }
diff --git a/third_party/WebKit/LayoutTests/animations/timing-functions.html b/third_party/WebKit/LayoutTests/animations/timing/timing-functions.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/animations/timing-functions.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-functions.html
index be5f041..81a74f2 100644
--- a/third_party/WebKit/LayoutTests/animations/timing-functions.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/timing-functions.html
@@ -80,7 +80,7 @@
     }
     
   </style>
-  <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script src="../resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
   <script type="text/javascript" charset="utf-8">
 
     const expectedValues = [
diff --git a/third_party/WebKit/LayoutTests/animations/timing-model-expected.txt b/third_party/WebKit/LayoutTests/animations/timing/timing-model-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/timing-model-expected.txt
rename to third_party/WebKit/LayoutTests/animations/timing/timing-model-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/timing-model.html b/third_party/WebKit/LayoutTests/animations/timing/timing-model.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/timing-model.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-model.html
diff --git a/third_party/WebKit/LayoutTests/animations/timing-properties-update-paused-animation.html b/third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-paused-animation.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/timing-properties-update-paused-animation.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-paused-animation.html
index 8d093d5f..9a3cdd3 100644
--- a/third_party/WebKit/LayoutTests/animations/timing-properties-update-paused-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-paused-animation.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim {
     from { background-color: blue; }
diff --git a/third_party/WebKit/LayoutTests/animations/timing-properties-update-running-animation.html b/third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-running-animation.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/animations/timing-properties-update-running-animation.html
rename to third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-running-animation.html
index 46b3d7b7..b23f5ba 100644
--- a/third_party/WebKit/LayoutTests/animations/timing-properties-update-running-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/timing/timing-properties-update-running-animation.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <style>
   @keyframes anim {
     from { left: 0px; }
diff --git a/third_party/WebKit/LayoutTests/animations/translate-neutral-keyframe-easing-expected.html b/third_party/WebKit/LayoutTests/animations/timing/translate-neutral-keyframe-easing-expected.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/translate-neutral-keyframe-easing-expected.html
rename to third_party/WebKit/LayoutTests/animations/timing/translate-neutral-keyframe-easing-expected.html
diff --git a/third_party/WebKit/LayoutTests/animations/translate-neutral-keyframe-easing.html b/third_party/WebKit/LayoutTests/animations/timing/translate-neutral-keyframe-easing.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/translate-neutral-keyframe-easing.html
rename to third_party/WebKit/LayoutTests/animations/timing/translate-neutral-keyframe-easing.html
diff --git a/third_party/WebKit/LayoutTests/animations/KeyframeEffectReadOnly-animation.html b/third_party/WebKit/LayoutTests/animations/web-animations/KeyframeEffectReadOnly-animation.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/animations/KeyframeEffectReadOnly-animation.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/KeyframeEffectReadOnly-animation.html
index 6cfba72..b9f20510 100644
--- a/third_party/WebKit/LayoutTests/animations/KeyframeEffectReadOnly-animation.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/KeyframeEffectReadOnly-animation.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Animating with KeyframeEffectReadOnly objects</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../external/wpt/web-animations/testcommon.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../external/wpt/web-animations/testcommon.js"></script>
 <body>
 <script>
 "use strict";
diff --git a/third_party/WebKit/LayoutTests/animations/animation-state-changes-negative-playback-rate.html b/third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-negative-playback-rate.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/animations/animation-state-changes-negative-playback-rate.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-negative-playback-rate.html
index 3f4f91d1..f5d57729 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-state-changes-negative-playback-rate.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-negative-playback-rate.html
@@ -2,9 +2,9 @@
 <meta charset=utf-8>
 <title>Test play state changes for animations with a negative playback rate</title>
 <link rel="help" href="http://w3c.github.io/web-animations/#play-state">
-<script src="../external/wpt/web-animations/testcommon.js"></script>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../external/wpt/web-animations/testcommon.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <script>
 var duration = 100000;
diff --git a/third_party/WebKit/LayoutTests/animations/animation-state-changes-positive-playback-rate.html b/third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-positive-playback-rate.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/animations/animation-state-changes-positive-playback-rate.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-positive-playback-rate.html
index fb9944d..db9910a8 100644
--- a/third_party/WebKit/LayoutTests/animations/animation-state-changes-positive-playback-rate.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/animation-state-changes-positive-playback-rate.html
@@ -2,9 +2,9 @@
 <meta charset=utf-8>
 <title>Tests for discrete animation</title>
 <link rel="help" href="https://w3c.github.io/web-animations/#play-state">
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../external/wpt/web-animations/testcommon.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../external/wpt/web-animations/testcommon.js"></script>
 <body>
 <script>
 'use strict';
diff --git a/third_party/WebKit/LayoutTests/animations/api-readonly-object-types.html b/third_party/WebKit/LayoutTests/animations/web-animations/api-readonly-object-types.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/animations/api-readonly-object-types.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/api-readonly-object-types.html
index f8b8297b..7e1ef50 100644
--- a/third_party/WebKit/LayoutTests/animations/api-readonly-object-types.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/api-readonly-object-types.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Read-only interface type tests</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../external/wpt/web-animations/testcommon.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../external/wpt/web-animations/testcommon.js"></script>
 <body>
 <script>
 "use strict";
diff --git a/third_party/WebKit/LayoutTests/animations/element-animate-iterable-keyframes.html b/third_party/WebKit/LayoutTests/animations/web-animations/element-animate-iterable-keyframes.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/animations/element-animate-iterable-keyframes.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/element-animate-iterable-keyframes.html
index a4c43ff..e447fb8 100644
--- a/third_party/WebKit/LayoutTests/animations/element-animate-iterable-keyframes.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/element-animate-iterable-keyframes.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body></body>
 <script>
 function assertAnimationEffect({keyframes, expect}) {
diff --git a/third_party/WebKit/LayoutTests/animations/element-animate-keyframe-value-warning-expected.txt b/third_party/WebKit/LayoutTests/animations/web-animations/element-animate-keyframe-value-warning-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/element-animate-keyframe-value-warning-expected.txt
rename to third_party/WebKit/LayoutTests/animations/web-animations/element-animate-keyframe-value-warning-expected.txt
diff --git a/third_party/WebKit/LayoutTests/animations/element-animate-keyframe-value-warning.html b/third_party/WebKit/LayoutTests/animations/web-animations/element-animate-keyframe-value-warning.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/animations/element-animate-keyframe-value-warning.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/element-animate-keyframe-value-warning.html
diff --git a/third_party/WebKit/LayoutTests/animations/keyframe-exceptions.html b/third_party/WebKit/LayoutTests/animations/web-animations/keyframe-exceptions.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/animations/keyframe-exceptions.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/keyframe-exceptions.html
index a72c5cb..ba08328 100644
--- a/third_party/WebKit/LayoutTests/animations/keyframe-exceptions.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/keyframe-exceptions.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
 <script>
 function assert_throws_with_message(e, f, m) {
diff --git a/third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html b/third_party/WebKit/LayoutTests/animations/web-animations/neutral-keyframe-easing.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/neutral-keyframe-easing.html
index 8d9a78d..905695b 100644
--- a/third_party/WebKit/LayoutTests/animations/neutral-keyframe-easing.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/neutral-keyframe-easing.html
@@ -1,5 +1,5 @@
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id="target"></div>
 <script>
 test(() => {
diff --git a/third_party/WebKit/LayoutTests/animations/the-effect-value-of-a-keyframe-effect.html b/third_party/WebKit/LayoutTests/animations/web-animations/the-effect-value-of-a-keyframe-effect.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/animations/the-effect-value-of-a-keyframe-effect.html
rename to third_party/WebKit/LayoutTests/animations/web-animations/the-effect-value-of-a-keyframe-effect.html
index ebcfb37b..5dc6253 100644
--- a/third_party/WebKit/LayoutTests/animations/the-effect-value-of-a-keyframe-effect.html
+++ b/third_party/WebKit/LayoutTests/animations/web-animations/the-effect-value-of-a-keyframe-effect.html
@@ -2,9 +2,9 @@
 <meta charset=utf-8>
 <title>Keyframe handling tests</title>
 <link rel="help" href="https://w3c.github.io/web-animations/#the-effect-value-of-a-keyframe-animation-effect">
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../external/wpt/web-animations/testcommon.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../external/wpt/web-animations/testcommon.js"></script>
 <body>
 <div id="log"></div>
 <div id="target"></div>
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-background-after-style-recalc-expected.png b/third_party/WebKit/LayoutTests/compositing/fixed-background-after-style-recalc-expected.png
index de6d6a5..e6a183b 100644
--- a/third_party/WebKit/LayoutTests/compositing/fixed-background-after-style-recalc-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/fixed-background-after-style-recalc-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.png b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.png
index 4c739d5..54e022a 100644
--- a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png
deleted file mode 100644
index b4f8cd3..0000000
--- a/third_party/WebKit/LayoutTests/compositing/img-layer-object-fit-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/css3/background/background-large-position-and-size-remains-stable-expected.png b/third_party/WebKit/LayoutTests/css3/background/background-large-position-and-size-remains-stable-expected.png
deleted file mode 100644
index ebb7c0b..0000000
--- a/third_party/WebKit/LayoutTests/css3/background/background-large-position-and-size-remains-stable-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/custom-elements/constructor-context-dies-then-retrieve-definition.html b/third_party/WebKit/LayoutTests/custom-elements/constructor-context-dies-then-retrieve-definition.html
new file mode 100644
index 0000000..75bf93f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/custom-elements/constructor-context-dies-then-retrieve-definition.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title id="t"></title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="spec/resources/custom-elements-helpers.js"></script>
+<body id="b">
+<script>
+test_with_window((w) => {
+  class X extends w.HTMLElement {}
+  t.appendChild(b);
+  // If the following line does not crash, the test passed.
+  w.customElements.define('a-a', X);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/dom/node/append_child_recurse_crash.html b/third_party/WebKit/LayoutTests/dom/node/append_child_recurse_crash.html
new file mode 100644
index 0000000..fddde18d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/dom/node/append_child_recurse_crash.html
@@ -0,0 +1,25 @@
+<!DOCTYPE>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div>
+<p id="parent">bar</p>
+<span id="test-title">title</span>
+</div>
+<script>
+test(() => {
+  var parent = document.querySelector('#parent');
+  var test_title = document.querySelector('#test-title');
+
+  // This function is called recursively.
+  function tCF_custom_1() {
+    var doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html');
+    doc.adoptNode(parent);
+    parent.appendChild(test_title);
+  }
+  parent.addEventListener('DOMSubtreeModified', tCF_custom_1, false);
+
+  parent.appendChild(test_title);
+}, 'Adopting parent node in DOMSubtreeModified event handler should not cause a crash.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html
new file mode 100644
index 0000000..7660c08d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on a fixed grid.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+  align-content: start;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+    <div style="top: 8px; left: 0px;">XX<br>XXXX<br>XX<br>XX X</div>
+    <div style="top: 0px; left: 50px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html
new file mode 100644
index 0000000..1e7138c9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on fixed-sized grid and content-distribution.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+  align-content: space-evenly;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 25px; left: 0px;">XX<br>XXXX<br>XX</div>
+  <div style="top: 73px; left: 0px;">XX X</div>
+  <div style="top: 17px; left: 50px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html
new file mode 100644
index 0000000..ce81285c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on fixed-sized grid and empty items .">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+  align-content: start;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+  font: 20px/1 Ahem;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 0px; width: 40px; background: red; height: 40px;"></div>
+  <div style="top: 24px; left: 50px" class="big">X</div>
+  <div style="top: 44px; left: 0px;">XX X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn" style="background: green; width: 40px; height: 40px;"></div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html
new file mode 100644
index 0000000..0dc218c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-004.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on auto-sized grid.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+  align-content: start;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 8px; left: 0px;">XX<br>XXXX<br>XX<br>XX X</div>
+  <div style="top: 0px; left: 50px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html
new file mode 100644
index 0000000..8570e7d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-005.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on auto-sized grid and gutters.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+  grid-row-gap: 20px;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 8px; left: 0px;">XX<br>XXXX<br>XX</div>
+  <div style="top: 58px; left: 0px;">XX X</div>
+  <div style="top: 0px; left: 50px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html
new file mode 100644
index 0000000..0b298a1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-006.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area height</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Column-Axis Self-Baseline alignment may change grid area height on auto-sized grid and empty items.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  font: 10px/1 Ahem;
+  color: green;
+  grid-auto-columns: 50px;
+  align-items: baseline;
+}
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 0px; width: 40px; background: red; height: 40px;"></div>
+  <div style="top: 24px; left: 50px" class="big">X</div>
+  <div style="top: 44px; left: 0px;">XX X</div>
+</div>
+<div class="grid"">
+  <div class="firstRowFirstColumn" style="background: green; width: 40px; height: 40px;"></div>
+  <div class="firstRowSecondColumn big">X</div>
+  <div class="secondRowFirstColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html
new file mode 100644
index 0000000..a91395e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on fixed-sized grid.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  justify-content: start;
+}
+.grid > div { writing-mode: vertical-lr; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 5px;">XXXX<br>XXXX</div>
+  <div style="top: 20px; left: 15px;">X</div>
+  <div style="top: 30px; left: 15px;">X X</div>
+  <div style="top: 50px; left: 0px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html
new file mode 100644
index 0000000..a707160
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on fixed-sized grid and content-distribution.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  justify-content: space-evenly;
+}
+.grid > div { writing-mode: vertical-lr; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 23px;">XXX<br>XXX</div>
+  <div style="top: 0px; left: 72px;">X</div>
+  <div style="top: 10px; left: 72px;">X</div>
+  <div style="top: 20px; left: 33px;">X</div>
+  <div style="top: 30px; left: 33px;">X</div>
+  <div style="top: 30px; left: 72px;">X</div>
+  <div style="top: 50px; left: 18px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html
new file mode 100644
index 0000000..67f421f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on fixed-sized grid and empty items.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: grid;
+  width: 100px;
+  height: 100px;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  justify-content: start;
+}
+.grid > div { writing-mode: vertical-lr; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 10px; width: 40px; background: red; height: 40px;"></div>
+  <div style="top: 0px; left: 50px;">X</div>
+  <div style="top: 10px; left: 50px;">X</div>
+  <div style="top: 30px; left: 50px;">X</div>
+  <div style="top: 50px; left: 0px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn" style="background: green; width: 40px; height: 40px;"></div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html
new file mode 100644
index 0000000..366cebb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on auto-sized grid.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  justify-content: start;
+}
+.grid > div { writing-mode: vertical-lr; }
+.big { font-size: 20px; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 5px;">XXXX<br>XXXX</div>
+  <div style="top: 20px; left: 15px;">X</div>
+  <div style="top: 30px; left: 15px;">X X</div>
+  <div style="top: 50px; left: 0px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html
new file mode 100644
index 0000000..5b407583c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on auto-sized grid and gutters.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  grid-column-gap: 20px;
+}
+.grid > div { writing-mode: vertical-lr; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 5px;">XXX<br>XXX</div>
+  <div style="top: 0px; left: 55px;">X</div>
+  <div style="top: 10px; left: 55px;">X</div>
+  <div style="top: 20px; left: 15px;">X</div>
+  <div style="top: 30px; left: 15px;">X</div>
+  <div style="top: 30px; left: 55px;">X</div>
+  <div style="top: 50px; left: 0px" class="big">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn">XX XXXX XX</div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html
new file mode 100644
index 0000000..d3b1274
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Self-Baseline alignment may change grid area width</title>
+<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#baseline-align-self">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#align-by-baseline">
+<link rel="match" href="../../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Row-Axis Self-Baseline alignment may change grid area width on auto-sized grid and empty items.">
+<style>
+.block, .grid { font: 10px/1 Ahem; }
+.big { font-size: 20px; }
+.block {
+  position: absolute;
+  z-index: -1;
+  background: green;
+  width: 100px;
+  height: 100px;
+}
+.block > div {
+  position: absolute;
+  color: red;
+}
+.grid {
+  display: inline-grid;
+  color: green;
+  grid-auto-rows: 50px;
+  justify-items: baseline;
+  justify-content: start;
+}
+.grid > div { writing-mode: vertical-lr; }
+.firstRowFirstColumn {
+  grid-row: 1;
+  grid-column: 1;
+}
+.secondRowFirstColumn {
+  grid-row: 2;
+  grid-column: 1;
+}
+.firstRowSecondColumn {
+  grid-row: 1;
+  grid-column: 2;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="block">
+  <div style="top: 0px; left: 10px; width: 40px; background: red; height: 40px;"></div>
+  <div style="top: 0px; left: 50px;">X</div>
+  <div style="top: 10px; left: 50px;">X</div>
+  <div style="top: 30px; left: 50px;">X</div>
+  <div style="top: 50px; left: 0px;">X</div>
+</div>
+<div class="grid">
+  <div class="firstRowFirstColumn" style="background: green; width: 40px; height: 40px;"></div>
+  <div class="secondRowFirstColumn big">X</div>
+  <div class="firstRowSecondColumn">XX X</div>
+</div>
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/external/wpt/navigation-timing/nav2_test_attributes_values.html b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_test_attributes_values.html
index a4b2f6a..6f46a4a0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_test_attributes_values.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/navigation-timing/nav2_test_attributes_values.html
@@ -50,6 +50,24 @@
             'connectEnd'
         ];
 
+        // Navigation Timing attributes for comparison.
+        var navTiming1EventOrder = [
+            'fetchStart',
+            'domainLookupStart',
+            'domainLookupEnd',
+            'connectStart',
+            'connectEnd',
+            'requestStart',
+            'responseStart',
+            'responseEnd',
+            'domInteractive',
+            'domContentLoadedEventStart',
+            'domContentLoadedEventEnd',
+            'domComplete',
+            'loadEventStart',
+            'loadEventEnd'
+        ];
+
         function verifyTimingEventOrder(eventOrder, timingEntry) {
             for (var i = 0; i < eventOrder.length - 1; i++) {
                 assert_true(timingEntry[eventOrder[i]] <= timingEntry[eventOrder[i + 1]],
@@ -75,9 +93,19 @@
                     // running this test.
                     assert_true(entries[0].transferSize > entries[0].encodedBodySize,
                         "Expected transferSize to be greater than encodedBodySize in uncached navigation.");
-                    assert_equals(entries[0].encodedBodySize, 4229);
-                    assert_equals(entries[0].decodedBodySize, 4229);
+                    assert_equals(entries[0].encodedBodySize, 5328);
+                    assert_equals(entries[0].decodedBodySize, 5328);
                     verifyTimingEventOrder(entries[0], navTiming2EventOrder1);
+                    // Verify if the reported timing is not that different
+                    // from what is reported by Navigation Timing 1.
+                    navTiming1EventOrder.forEach(
+                      function(event) {
+                        if (window.performance.timing[event] -
+                            window.performance.timing.navigationStart > 0) {
+                          assert_greater_than(entries[0][event], 0,
+                              "Expected " + event + " to be greater than 0");
+                        }
+                    });
                     // When unloadEvent happens
                     if (entries[0]["unloadEventStart"] != 0) {
                         verifyTimingEventOrder(entries[0], navTiming2EventOrder2);
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/mask-box-image-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/mask-box-image-expected.png
index 7964104..e8c9508 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/mask-box-image-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/mask-box-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize02-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize02-expected.png
index 5e12542..0adfbce 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize02-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize02-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize04-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize04-expected.png
index ca29b6b..d5ccc21 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize04-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize04-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize13-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize13-expected.png
index a2da786..127759c 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize13-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize13-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize14-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize14-expected.png
index dd52f47..9aa36a2 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize14-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/backgroundSize14-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
index dcba2fd..dbc062c1 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
index 6eadbea..ce608f7 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/block/positioning/replaced-inside-fixed-top-bottom-expected.png b/third_party/WebKit/LayoutTests/fast/block/positioning/replaced-inside-fixed-top-bottom-expected.png
index e38e739c1..1bc2f095 100644
--- a/third_party/WebKit/LayoutTests/fast/block/positioning/replaced-inside-fixed-top-bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/block/positioning/replaced-inside-fixed-top-bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-01-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-01-expected.png
deleted file mode 100644
index d6c4262e..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-01-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-longhand-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-longhand-expected.png
deleted file mode 100644
index d6c4262e..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-longhand-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-massive-scale-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-massive-scale-expected.png
deleted file mode 100644
index bc4d542..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-massive-scale-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-omit-right-slice-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-omit-right-slice-expected.png
index 22f3f88d9..9379b4c0 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-omit-right-slice-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-image-omit-right-slice-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-expected.png
deleted file mode 100644
index 9a4c0a8..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-in-shorthand-expected.png
deleted file mode 100644
index 9a4c0a8..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-outset-in-shorthand-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-repeat-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-repeat-expected.png
deleted file mode 100644
index d6c4262e..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-rotate-transform-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-rotate-transform-expected.png
deleted file mode 100644
index d2d882f..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-rotate-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-scale-transform-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-scale-transform-expected.png
deleted file mode 100644
index 96bfcf1..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-scale-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-scrambled-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-scrambled-expected.png
deleted file mode 100644
index d6c4262e..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-scrambled-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png
deleted file mode 100644
index b5d6c621..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-side-reduction-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-slices-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-slices-expected.png
deleted file mode 100644
index 48b6e16..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-slices-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-image-source-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-image-source-expected.png
deleted file mode 100644
index d6c4262e..0000000
--- a/third_party/WebKit/LayoutTests/fast/borders/border-image-source-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/fast/canvas/canvas-toDataURL-webp-expected.png
index ca943d55..b3a70eaa 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
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 31554f82..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/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-edge-expected.png
index b1251809..99aee99 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-iframe-expected.png
index 4aedf2ad..23b5a1b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index 0d30cd6..8abc332 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/loader/stateobjects/spam-pushstate-then-throttled.html b/third_party/WebKit/LayoutTests/fast/loader/stateobjects/spam-pushstate-then-throttled.html
new file mode 100644
index 0000000..2805f86
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/loader/stateobjects/spam-pushstate-then-throttled.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+'use strict';
+
+// This value must match that in Source/core/frame/History.cpp.
+const kStateUpdateLimit = 50;
+for (let i = 0; i < kStateUpdateLimit; ++i) {
+  history.pushState("SpammyHistoryItem", "" + i);
+}
+assert_equals(kStateUpdateLimit, history.length);
+
+history.pushState("DiscardedSpamItem", "51");
+assert_equals(kStateUpdateLimit, history.length);
+
+done();
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/writing-mode/block-level-images-expected.png b/third_party/WebKit/LayoutTests/fast/writing-mode/block-level-images-expected.png
index fdf67faa..ce8204e 100644
--- a/third_party/WebKit/LayoutTests/fast/writing-mode/block-level-images-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/writing-mode/block-level-images-expected.png
Binary files differ
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 0c77166f..3eb5d6c 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -38,22 +40,21 @@
     setTimeout(fn, milliseconds);
 }
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(31.478, -0.166, 100);
-    mock.setGeolocationPermission(true);
+let mock = geolocationMock;
+mock.setGeolocationPosition(31.478, -0.166, 100);
+mock.setGeolocationPermission(true);
 
-    // Make a geolocation request to populate the cached value so requests with a
-    // timeout of 0 can succeed.
-    navigator.geolocation.getCurrentPosition(function(position) {
-        // The test terminates at the 3rd reported callback. If the bug still exists
-        // this happens after the 2nd call to getCurrentPosition, one of them is a
-        // repeat of the first.
-        getPosition(0);
-        getPosition(100);
-        getPosition(200);
-    }, function(error) {
-        testFailed('Error callback invoked unexpectedly');
-    });
+// Make a geolocation request to populate the cached value so requests with a
+// timeout of 0 can succeed.
+navigator.geolocation.getCurrentPosition(function(position) {
+    // The test terminates at the 3rd reported callback. If the bug still exists
+    // this happens after the 2nd call to getCurrentPosition, one of them is a
+    // repeat of the first.
+    getPosition(0);
+    getPosition(100);
+    getPosition(200);
+}, function(error) {
+    testFailed('Error callback invoked unexpectedly');
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception-expected.txt b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception-expected.txt
index 6aab36a..8637481e 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception-expected.txt
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 34: Uncaught Error: Exception in success callback
+CONSOLE ERROR: line 36: Uncaught Error: Exception in success callback
 Tests that when an exception is thrown in the success callback, the error callback is not invoked. Note that this test throws an exception which is not caught.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
index 7b533bd8..3cbc2e0d 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-exception.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,27 +17,26 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
-    navigator.geolocation.getCurrentPosition(function(p) {
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
+navigator.geolocation.getCurrentPosition(function(p) {
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
 
-        // Yield to allow for the error callback to be invoked. The timer
-        // must be started before the exception is thrown.
-        window.setTimeout(assertWeGotException, 0);
-        expectError();
+    // Yield to allow for the error callback to be invoked. The timer
+    // must be started before the exception is thrown.
+    window.setTimeout(assertWeGotException, 0);
+    expectError();
 
-        throw new Error('Exception in success callback');
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
+    throw new Error('Exception in success callback');
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
 function assertWeGotException()
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..2a0b104a 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -21,12 +23,11 @@
 }
 
 var iframe = document.createElement('iframe');
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
-    iframe.src = 'resources/callback-to-deleted-context-inner1.html';
-    document.body.appendChild(iframe);
-});
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(51.478, -0.166, 100);
+iframe.src = 'resources/callback-to-deleted-context-inner1.html';
+document.body.appendChild(iframe);
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context.html b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context.html
index ccd1f211..445a4c43 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context.html
@@ -2,8 +2,6 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
-<script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context2.html b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context2.html
index 6c1d1b58..8c4a9d8 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context2.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/callback-to-remote-context2.html
@@ -2,8 +2,6 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
-<script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
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..60da92c5 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -13,14 +15,13 @@
   debug('This test can not run without testRunner');
 
 document.body.onload = function() {
-    geolocationServiceMock.then(mock => {
-        mock.setGeolocationPermission(true);
-        mock.setGeolocationPosition(51.478, -0.166, 100);
+    let mock = geolocationMock;
+    mock.setGeolocationPermission(true);
+    mock.setGeolocationPosition(51.478, -0.166, 100);
 
-        navigator.geolocation.watchPosition(function() {});
-        navigator.geolocation.clearWatch(0);
-        location = "../resources/notify-success.html";
-    });
+    navigator.geolocation.watchPosition(function() {});
+    navigator.geolocation.clearWatch(0);
+    location = "../resources/notify-success.html";
 }
 
 window.jsTestIsAsync = true;
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 6db76c21..9b287602 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/coordinates-interface-attributes.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -24,44 +26,43 @@
 var currentTestIndex = -1;
 var globalCoordinates = null;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
 
-    function runNextTest()
-    {
-        ++currentTestIndex;
-        mock.setGeolocationPosition(...testSet[currentTestIndex][0]);
-    }
+function runNextTest()
+{
+    ++currentTestIndex;
+    mock.setGeolocationPosition(...testSet[currentTestIndex][0]);
+}
 
-    function verifyResults()
-    {
-        shouldBe('globalCoordinates.latitude', 'testSet[currentTestIndex][1][0]');
-        shouldBe('globalCoordinates.longitude', 'testSet[currentTestIndex][1][1]');
-        shouldBe('globalCoordinates.accuracy', 'testSet[currentTestIndex][1][2]');
-        shouldBe('globalCoordinates.altitude', 'testSet[currentTestIndex][1][3]');
-        shouldBe('globalCoordinates.altitudeAccuracy', 'testSet[currentTestIndex][1][4]');
-        shouldBe('globalCoordinates.heading', 'testSet[currentTestIndex][1][5]');
-        shouldBe('globalCoordinates.speed', 'testSet[currentTestIndex][1][6]');
-        debug('');
-    }
+function verifyResults()
+{
+    shouldBe('globalCoordinates.latitude', 'testSet[currentTestIndex][1][0]');
+    shouldBe('globalCoordinates.longitude', 'testSet[currentTestIndex][1][1]');
+    shouldBe('globalCoordinates.accuracy', 'testSet[currentTestIndex][1][2]');
+    shouldBe('globalCoordinates.altitude', 'testSet[currentTestIndex][1][3]');
+    shouldBe('globalCoordinates.altitudeAccuracy', 'testSet[currentTestIndex][1][4]');
+    shouldBe('globalCoordinates.heading', 'testSet[currentTestIndex][1][5]');
+    shouldBe('globalCoordinates.speed', 'testSet[currentTestIndex][1][6]');
+    debug('');
+}
 
-    var watchId = navigator.geolocation.watchPosition(function(position) {
-        globalCoordinates = position.coords;
-        verifyResults();
+var watchId = navigator.geolocation.watchPosition(function(position) {
+    globalCoordinates = position.coords;
+    verifyResults();
 
-        if (currentTestIndex + 1 === testSet.length) {
-            finishJSTest();
-            return;
-        }
-        runNextTest();
-    }, function(e) {
-        debug("Error!: the error callback was called.");
+    if (currentTestIndex + 1 === testSet.length) {
         finishJSTest();
-    });
-
+        return;
+    }
     runNextTest();
+}, function(e) {
+    debug("Error!: the error callback was called.");
+    finishJSTest();
 });
 
+runNextTest();
+
 </script>
 </body>
 </html>
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..1f84e61 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
@@ -2,62 +2,63 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
 description("Tests that when multiple requests are waiting for permission, no callbacks are invoked until permission is allowed.");
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    var permissionSet = false;
+var permissionSet = false;
 
-    function allowPermission() {
-        permissionSet = true;
-        mock.setGeolocationPermission(true);
+function allowPermission() {
+    permissionSet = true;
+    mock.setGeolocationPermission(true);
+}
+
+var watchCallbackInvoked = false;
+var oneShotCallbackInvoked = false;
+
+navigator.geolocation.watchPosition(function() {
+    if (permissionSet) {
+        testPassed('Success callback invoked');
+        watchCallbackInvoked = true;
+        maybeFinishTest();
+        return;
     }
-
-    var watchCallbackInvoked = false;
-    var oneShotCallbackInvoked = false;
-
-    navigator.geolocation.watchPosition(function() {
-        if (permissionSet) {
-            testPassed('Success callback invoked');
-            watchCallbackInvoked = true;
-            maybeFinishTest();
-            return;
-        }
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(err) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-
-    navigator.geolocation.getCurrentPosition(function() {
-        if (permissionSet) {
-            testPassed('Success callback invoked');
-            oneShotCallbackInvoked = true;
-            maybeFinishTest();
-            return;
-        }
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(err) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-
-    window.setTimeout(allowPermission, 100);
-
-    function maybeFinishTest() {
-        if (watchCallbackInvoked && oneShotCallbackInvoked)
-            finishJSTest();
-    }
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(err) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
+navigator.geolocation.getCurrentPosition(function() {
+    if (permissionSet) {
+        testPassed('Success callback invoked');
+        oneShotCallbackInvoked = true;
+        maybeFinishTest();
+        return;
+    }
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(err) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+});
+
+window.setTimeout(allowPermission, 100);
+
+function maybeFinishTest() {
+    if (watchCallbackInvoked && oneShotCallbackInvoked)
+        finishJSTest();
+}
+
 window.jsTestIsAsync = true;
 </script>
 </body>
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..17143e1 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-allowed.html
@@ -2,37 +2,38 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
 description("Tests that when a position is available, no callbacks are invoked until permission is allowed.");
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    var permissionSet = false;
+var permissionSet = false;
 
-    function allowPermission() {
-        permissionSet = true;
-        mock.setGeolocationPermission(true);
+function allowPermission() {
+    permissionSet = true;
+    mock.setGeolocationPermission(true);
+}
+
+navigator.geolocation.getCurrentPosition(function() {
+    if (permissionSet) {
+        testPassed('Success callback invoked');
+        finishJSTest();
+        return;
     }
-
-    navigator.geolocation.getCurrentPosition(function() {
-        if (permissionSet) {
-            testPassed('Success callback invoked');
-            finishJSTest();
-            return;
-        }
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function() {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-    window.setTimeout(allowPermission, 100);
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function() {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
+window.setTimeout(allowPermission, 100);
 
 window.jsTestIsAsync = true;
 </script>
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..21cb4882 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,58 +13,57 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    var permissionSet = false;
+var permissionSet = false;
 
-    function denyPermission() {
-        permissionSet = true;
-        mock.setGeolocationPermission(false);
+function denyPermission() {
+    permissionSet = true;
+    mock.setGeolocationPermission(false);
+}
+
+var watchCallbackInvoked = false;
+var oneShotCallbackInvoked = false;
+
+navigator.geolocation.watchPosition(function() {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (permissionSet) {
+        error = e;
+        shouldBe('error.code', 'error.PERMISSION_DENIED');
+        shouldBe('error.message', '"User denied Geolocation"');
+        watchCallbackInvoked = true;
+        maybeFinishTest();
+        return;
     }
-
-    var watchCallbackInvoked = false;
-    var oneShotCallbackInvoked = false;
-
-    navigator.geolocation.watchPosition(function() {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        if (permissionSet) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            watchCallbackInvoked = true;
-            maybeFinishTest();
-            return;
-        }
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-
-    navigator.geolocation.getCurrentPosition(function() {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        if (permissionSet) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            oneShotCallbackInvoked = true;
-            maybeFinishTest();
-            return;
-        }
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-    window.setTimeout(denyPermission, 100);
-
-    function maybeFinishTest() {
-        if (watchCallbackInvoked && oneShotCallbackInvoked)
-            finishJSTest();
-    }
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
+navigator.geolocation.getCurrentPosition(function() {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (permissionSet) {
+        error = e;
+        shouldBe('error.code', 'error.PERMISSION_DENIED');
+        shouldBe('error.message', '"User denied Geolocation"');
+        oneShotCallbackInvoked = true;
+        maybeFinishTest();
+        return;
+    }
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+});
+window.setTimeout(denyPermission, 100);
+
+function maybeFinishTest() {
+    if (watchCallbackInvoked && oneShotCallbackInvoked)
+        finishJSTest();
+}
+
 window.jsTestIsAsync = true;
 </script>
 </body>
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..920ce1d 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/delayed-permission-denied.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,32 +13,31 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    var permissionSet = false;
+var permissionSet = false;
 
-    function denyPermission() {
-        permissionSet = true;
-        mock.setGeolocationPermission(false);
+function denyPermission() {
+    permissionSet = true;
+    mock.setGeolocationPermission(false);
+}
+
+navigator.geolocation.getCurrentPosition(function() {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (permissionSet) {
+        error = e;
+        shouldBe('error.code', 'error.PERMISSION_DENIED');
+        shouldBe('error.message', '"User denied Geolocation"');
+        finishJSTest();
+        return;
     }
-
-    navigator.geolocation.getCurrentPosition(function() {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        if (permissionSet) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            finishJSTest();
-            return;
-        }
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-    window.setTimeout(denyPermission, 100);
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
+window.setTimeout(denyPermission, 100);
 
 window.jsTestIsAsync = true;
 </script>
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..5cc140d 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame-already.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,13 +13,12 @@
 
 var iframe = document.createElement('iframe');
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    iframe.src = 'resources/disconnected-frame-already-inner1.html';
-    document.body.appendChild(iframe);
-});
+iframe.src = 'resources/disconnected-frame-already-inner1.html';
+document.body.appendChild(iframe);
 
 function onFirstIframeLoaded() {
     iframeGeolocation = iframe.contentWindow.navigator.geolocation;
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..48d22480 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -42,15 +44,14 @@
 }
 
 
-geolocationServiceMock.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);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+// 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.
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    iframe.src = 'resources/disconnected-frame-inner.html';
-    document.body.appendChild(iframe);
-});
+iframe.src = 'resources/disconnected-frame-inner.html';
+document.body.appendChild(iframe);
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
index 899a3fc..9a3a5d3 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/disconnected-frame.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -31,13 +33,13 @@
     }, 100);
 }
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    iframe.src = 'resources/disconnected-frame-inner.html';
-    document.body.appendChild(iframe);
-});
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(51.478, -0.166, 100);
+
+iframe.src = 'resources/disconnected-frame-inner.html';
+document.body.appendChild(iframe);
 
 window.jsTestIsAsync = true;
 </script>
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..d8fc6d9 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/error-clear-watch.html
@@ -2,27 +2,27 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
 description("This tests removing the watcher from an error callback does not causes assertions.");
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPositionUnavailableError("debug");
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPositionUnavailableError("debug");
 
-    var watchId = navigator.geolocation.watchPosition(function() {
-        navigator.geolocation.clearWatch(watchId);
-        finishJSTest();
-    }, function(e) {
-        navigator.geolocation.clearWatch(watchId);
-        finishJSTest();
-    });
+var watchId = navigator.geolocation.watchPosition(function() {
+    navigator.geolocation.clearWatch(watchId);
+    finishJSTest();
+}, function(e) {
+    navigator.geolocation.clearWatch(watchId);
+    finishJSTest();
 });
 
-
 window.jsTestIsAsync = true;
 </script>
 </body>
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..50ed6819 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,19 +13,18 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-  mock.setGeolocationPermission(true);
-  mock.rejectGeolocationConnections();
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.rejectGeolocationConnections();
 
-  navigator.geolocation.getCurrentPosition(function(p) {
-    testFailed('Success callback invoked unexpectedly');
-    finishJSTest();
-  }, function(e) {
-    error = e;
-    shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
-    shouldBe('error.message', '"Failed to start Geolocation service"');
-    finishJSTest();
-  });
+navigator.geolocation.getCurrentPosition(function(p) {
+  testFailed('Success callback invoked unexpectedly');
+  finishJSTest();
+}, function(e) {
+  error = e;
+  shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
+  shouldBe('error.message', '"Failed to start Geolocation service"');
+  finishJSTest();
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/error.html b/third_party/WebKit/LayoutTests/geolocation-api/error.html
index 73ddb28c..7017e01 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/error.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -13,23 +15,22 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-  mock.setGeolocationPermission(true);
-  mock.setGeolocationPositionUnavailableError(mockMessage);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPositionUnavailableError(mockMessage);
 
-  navigator.geolocation.getCurrentPosition(function(p) {
-    testFailed('Success callback invoked unexpectedly');
-    finishJSTest();
-  }, function(e) {
-    error = e;
-    shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
-    shouldBe('error.message', 'mockMessage');
-    shouldBe('error.UNKNOWN_ERROR', 'undefined');
-    shouldBe('error.PERMISSION_DENIED', '1');
-    shouldBe('error.POSITION_UNAVAILABLE', '2');
-    shouldBe('error.TIMEOUT', '3');
-    finishJSTest();
-  });
+navigator.geolocation.getCurrentPosition(function(p) {
+  testFailed('Success callback invoked unexpectedly');
+  finishJSTest();
+}, function(e) {
+  error = e;
+  shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
+  shouldBe('error.message', 'mockMessage');
+  shouldBe('error.UNKNOWN_ERROR', 'undefined');
+  shouldBe('error.PERMISSION_DENIED', '1');
+  shouldBe('error.POSITION_UNAVAILABLE', '2');
+  shouldBe('error.TIMEOUT', '3');
+  finishJSTest();
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html b/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
index 983dec7..23625ce 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/maximum-age.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -33,95 +35,94 @@
     shouldBe('error.message', 'mockMessage');
 }
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-    // Initialize the cached Position
+// Initialize the cached Position
+navigator.geolocation.getCurrentPosition(function(p) {
+    checkPosition(p);
+    testZeroMaximumAge();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+});
+
+function testZeroMaximumAge() {
+    // Update the position provided by the mock service.
+    mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
+    // The default maximumAge is zero, so we expect the updated position from the service.
     navigator.geolocation.getCurrentPosition(function(p) {
         checkPosition(p);
-        testZeroMaximumAge();
+        testNonZeroMaximumAge();
     }, function(e) {
         testFailed('Error callback invoked unexpectedly');
         finishJSTest();
     });
+}
 
-    function testZeroMaximumAge() {
-        // Update the position provided by the mock service.
-        mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
-        // The default maximumAge is zero, so we expect the updated position from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            checkPosition(p);
-            testNonZeroMaximumAge();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        });
-    }
+function testNonZeroMaximumAge() {
+    // Update the mock service to report an error.
+    mock.setGeolocationPositionUnavailableError(mockMessage);
+    // The maximumAge is non-zero, so we expect the cached position, not the error from the service.
+    navigator.geolocation.getCurrentPosition(function(p) {
+        checkPosition(p);
+        testNegativeValueMaximumAge();
+    }, function(e) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
+    }, {maximumAge: 1000});
+}
 
-    function testNonZeroMaximumAge() {
-        // Update the mock service to report an error.
-        mock.setGeolocationPositionUnavailableError(mockMessage);
-        // The maximumAge is non-zero, so we expect the cached position, not the error from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            checkPosition(p);
-            testNegativeValueMaximumAge();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }, {maximumAge: 1000});
-    }
+function testNegativeValueMaximumAge() {
+    // Update the position provided by the mock service.
+    mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
+    // The maximumAge is same as zero, so we expect the updated position from the service.
+    navigator.geolocation.getCurrentPosition(function(p) {
+        checkPosition(p);
+        testOverSignedIntMaximumAge();
+    }, function(e) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
+    }, {maximumAge: -1000});
+}
 
-    function testNegativeValueMaximumAge() {
-        // Update the position provided by the mock service.
-        mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
-        // The maximumAge is same as zero, so we expect the updated position from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            checkPosition(p);
-            testOverSignedIntMaximumAge();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }, {maximumAge: -1000});
-    }
+function testOverSignedIntMaximumAge() {
+    // Update the mock service to report an error.
+    mock.setGeolocationPositionUnavailableError(mockMessage);
+    // The maximumAge is non-zero, so we expect the cached position, not the error from the service.
+    navigator.geolocation.getCurrentPosition(function(p) {
+        checkPosition(p);
+        testOverUnsignedIntMaximumAge();
+    }, function(e) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
+    }, {maximumAge: 2147483648});
+}
 
-    function testOverSignedIntMaximumAge() {
-        // Update the mock service to report an error.
-        mock.setGeolocationPositionUnavailableError(mockMessage);
-        // The maximumAge is non-zero, so we expect the cached position, not the error from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            checkPosition(p);
-            testOverUnsignedIntMaximumAge();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }, {maximumAge: 2147483648});
-    }
+function testOverUnsignedIntMaximumAge() {
+    // Update the mock service to report an error.
+    mock.setGeolocationPositionUnavailableError(mockMessage);
+    // The maximumAge is max-value of unsigned, so we expect the cached position, not the error from the service.
+    navigator.geolocation.getCurrentPosition(function(p) {
+        checkPosition(p);
+        testZeroMaximumAgeError();
+    }, function(e) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
+    }, {maximumAge: 4294967296});
+}
 
-    function testOverUnsignedIntMaximumAge() {
-        // Update the mock service to report an error.
-        mock.setGeolocationPositionUnavailableError(mockMessage);
-        // The maximumAge is max-value of unsigned, so we expect the cached position, not the error from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            checkPosition(p);
-            testZeroMaximumAgeError();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }, {maximumAge: 4294967296});
-    }
-
-    function testZeroMaximumAgeError() {
-        // The default maximumAge is zero, so we expect the error from the service.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            checkError(e);
-            finishJSTest();
-        });
-    }
-});
+function testZeroMaximumAgeError() {
+    // The default maximumAge is zero, so we expect the error from the service.
+    navigator.geolocation.getCurrentPosition(function(p) {
+        testFailed('Success callback invoked unexpectedly');
+        finishJSTest();
+    }, function(e) {
+        checkError(e);
+        finishJSTest();
+    });
+}
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html b/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
index f288f42..6f0c8c3f0 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/multiple-requests.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -17,38 +19,37 @@
 var watchCallbackInvoked = false;
 var oneShotCallbackInvoked = false;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-    navigator.geolocation.watchPosition(function(p) {
-        shouldBeFalse('watchCallbackInvoked');
-        watchCallbackInvoked = true;
-        maybeFinishTest(p);
-    }, function() {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-
-    navigator.geolocation.getCurrentPosition(function(p) {
-        shouldBeFalse('oneShotCallbackInvoked');
-        oneShotCallbackInvoked = true;
-        maybeFinishTest(p);
-    }, function() {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
-
-    function maybeFinishTest(p) {
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
-        if (watchCallbackInvoked && oneShotCallbackInvoked)
-            finishJSTest();
-    }
+navigator.geolocation.watchPosition(function(p) {
+    shouldBeFalse('watchCallbackInvoked');
+    watchCallbackInvoked = true;
+    maybeFinishTest(p);
+}, function() {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
+navigator.geolocation.getCurrentPosition(function(p) {
+    shouldBeFalse('oneShotCallbackInvoked');
+    oneShotCallbackInvoked = true;
+    maybeFinishTest(p);
+}, function() {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+});
+
+function maybeFinishTest(p) {
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    if (watchCallbackInvoked && oneShotCallbackInvoked)
+        finishJSTest();
+}
+
 window.jsTestIsAsync = true;
 </script>
 </body>
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..ce58240 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/notimer-after-unload.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -12,11 +14,9 @@
 if (!window.testRunner)
   debug('This test can not run without testRunner');
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
+geolocationMock.setGeolocationPermission(true);
 
-    location = "../fast/events/resources/onunload-single-alert-success.html";
-});
+location = "../fast/events/resources/onunload-single-alert-success.html";
 
 document.body.onunload = function() {
     navigator.geolocation.getCurrentPosition(
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..1a5a24a 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,38 +13,36 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+// Prime the Geolocation instance by denying permission.
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    // Prime the Geolocation instance by denying permission.
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+    debug('');
+    continueTest();
+});
 
-    navigator.geolocation.getCurrentPosition(function(p) {
+function continueTest()
+{
+    // Make another request, with permission already denied.
+    var watchId = navigator.geolocation.watchPosition(function(p) {
         testFailed('Success callback invoked unexpectedly');
         finishJSTest();
     }, function(e) {
         error = e;
         shouldBe('error.code', 'error.PERMISSION_DENIED');
         shouldBe('error.message', '"User denied Geolocation"');
-        debug('');
-        continueTest();
+        navigator.geolocation.clearWatch(watchId);
+        window.setTimeout(finishJSTest, 0);
     });
-
-    function continueTest()
-    {
-        // Make another request, with permission already denied.
-        var watchId = navigator.geolocation.watchPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            navigator.geolocation.clearWatch(watchId);
-            window.setTimeout(finishJSTest, 0);
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
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..cf7c609c 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,9 +13,25 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100);
+
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+    debug('');
+    continueTest();
+});
+
+function continueTest()
+{
+    // Make another request, with permission already denied.
+    mock.setGeolocationPositionUnavailableError('test');
 
     navigator.geolocation.getCurrentPosition(function(p) {
         testFailed('Success callback invoked unexpectedly');
@@ -22,26 +40,9 @@
         error = e;
         shouldBe('error.code', 'error.PERMISSION_DENIED');
         shouldBe('error.message', '"User denied Geolocation"');
-        debug('');
-        continueTest();
+        finishJSTest();
     });
-
-    function continueTest()
-    {
-        // Make another request, with permission already denied.
-        mock.setGeolocationPositionUnavailableError('test');
-
-        navigator.geolocation.getCurrentPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            finishJSTest();
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
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..8ad8165 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,12 +13,25 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+// Prime the Geolocation instance by denying permission.
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100);
 
-    // Prime the Geolocation instance by denying permission.
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100);
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+    debug('');
+    continueTest();
+});
 
+function continueTest()
+{
+    // Make another request, with permission already denied.
     navigator.geolocation.getCurrentPosition(function(p) {
         testFailed('Success callback invoked unexpectedly');
         finishJSTest();
@@ -24,24 +39,9 @@
         error = e;
         shouldBe('error.code', 'error.PERMISSION_DENIED');
         shouldBe('error.message', '"User denied Geolocation"');
-        debug('');
-        continueTest();
+        finishJSTest();
     });
-
-    function continueTest()
-    {
-        // Make another request, with permission already denied.
-        navigator.geolocation.getCurrentPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            error = e;
-            shouldBe('error.code', 'error.PERMISSION_DENIED');
-            shouldBe('error.message', '"User denied Geolocation"');
-            finishJSTest();
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
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..d93568a 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,33 +13,31 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+// Configure the mock Geolocation service to report a position to cause permission
+// to be requested, then deny it.
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    // Configure the mock Geolocation service to report a position to cause permission
-    // to be requested, then deny it.
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
-
-    var errorCallbackInvoked = false;
-    navigator.geolocation.watchPosition(function(p) {
-        testFailed('Success callback invoked unexpectedly');
+var errorCallbackInvoked = false;
+navigator.geolocation.watchPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (errorCallbackInvoked) {
+        testFailed('Error callback invoked unexpectedly : ' + error.message);
         finishJSTest();
-    }, function(e) {
-        if (errorCallbackInvoked) {
-            testFailed('Error callback invoked unexpectedly : ' + error.message);
-            finishJSTest();
-        }
-        errorCallbackInvoked = true;
+    }
+    errorCallbackInvoked = true;
 
-        error = e;
-        shouldBe('error.code', 'error.PERMISSION_DENIED');
-        shouldBe('error.message', '"User denied Geolocation"');
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
 
-        // Update the mock Geolocation service to report a new position, then
-        // yield to allow a chance for the success callback to be invoked.
-        mock.setGeolocationPosition(55.478, -0.166, 100);
-        window.setTimeout(finishJSTest, 0);
-    });
+    // Update the mock Geolocation service to report a new position, then
+    // yield to allow a chance for the success callback to be invoked.
+    mock.setGeolocationPosition(55.478, -0.166, 100);
+    window.setTimeout(finishJSTest, 0);
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
index 28a54ee..f740d6e 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/permission-denied.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,20 +13,18 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
-
-    navigator.geolocation.getCurrentPosition(function(p) {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        error = e;
-        shouldBe('error.code', 'error.PERMISSION_DENIED');
-        shouldBe('error.message', '"User denied Geolocation"');
-        finishJSTest();
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+    finishJSTest();
 });
 
 window.jsTestIsAsync = true;
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..1ff2605a 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,19 +13,16 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
+geolocationMock.rejectPermissionConnections();
 
-    mock.rejectPermissionConnections();
-
-    navigator.geolocation.getCurrentPosition(function(p) {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        error = e;
-        shouldBe('error.code', 'error.PERMISSION_DENIED');
-        shouldBe('error.message', '"User denied Geolocation"');
-        finishJSTest();
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+    finishJSTest();
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/position-string.html b/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
index 665d4f1a..0705ec4 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/position-string.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,25 +17,24 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        // shouldBe can't use local variables yet.
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
-        shouldBe('position.toString()', '"[object Position]"');
-        shouldBe('position.coords.toString()', '"[object Coordinates]"');
-        finishJSTest();
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    // shouldBe can't use local variables yet.
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    shouldBe('position.toString()', '"[object Position]"');
+    shouldBe('position.coords.toString()', '"[object Coordinates]"');
+    finishJSTest();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
index 2034b9ec..a445e2c4 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-error.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -13,44 +15,43 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPositionUnavailableError(mockMessage);
+
+var errorCallbackInvoked = false;
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (errorCallbackInvoked) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
+    }
+    errorCallbackInvoked = true;
+
+    error = e;
+    shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
+    shouldBe('error.message', 'mockMessage');
+    debug('');
+    continueTest();
+});
+
+function continueTest() {
+    mockMessage += ' repeat';
+
     mock.setGeolocationPositionUnavailableError(mockMessage);
 
-    var errorCallbackInvoked = false;
     navigator.geolocation.getCurrentPosition(function(p) {
         testFailed('Success callback invoked unexpectedly');
         finishJSTest();
     }, function(e) {
-        if (errorCallbackInvoked) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }
-        errorCallbackInvoked = true;
-
         error = e;
         shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
         shouldBe('error.message', 'mockMessage');
-        debug('');
-        continueTest();
+        finishJSTest();
     });
-
-    function continueTest() {
-        mockMessage += ' repeat';
-
-        mock.setGeolocationPositionUnavailableError(mockMessage);
-
-        navigator.geolocation.getCurrentPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            error = e;
-            shouldBe('error.code', 'error.POSITION_UNAVAILABLE');
-            shouldBe('error.message', 'mockMessage');
-            finishJSTest();
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
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..7d8b9881 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-permission-denied.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,40 +13,39 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(false);
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
+let mock = geolocationMock;
+mock.setGeolocationPermission(false);
+mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    function checkPermissionError(e) {
-        error = e;
-        shouldBe('error.code', 'error.PERMISSION_DENIED');
-        shouldBe('error.message', '"User denied Geolocation"');
+function checkPermissionError(e) {
+    error = e;
+    shouldBe('error.code', 'error.PERMISSION_DENIED');
+    shouldBe('error.message', '"User denied Geolocation"');
+}
+
+var errorCallbackInvoked = false;
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    if (errorCallbackInvoked) {
+        testFailed('Error callback invoked unexpectedly');
+        finishJSTest();
     }
+    errorCallbackInvoked = true;
+    checkPermissionError(e);
+    continueTest();
+});
 
-    var errorCallbackInvoked = false;
+function continueTest() {
     navigator.geolocation.getCurrentPosition(function(p) {
         testFailed('Success callback invoked unexpectedly');
         finishJSTest();
     }, function(e) {
-        if (errorCallbackInvoked) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        }
-        errorCallbackInvoked = true;
         checkPermissionError(e);
-        continueTest();
+        finishJSTest();
     });
-
-    function continueTest() {
-        navigator.geolocation.getCurrentPosition(function(p) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }, function(e) {
-            checkPermissionError(e);
-            finishJSTest();
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
index 94e91da2..7e15fa54 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/reentrant-success.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,48 +17,47 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    var successCallbackInvoked = false;
+var successCallbackInvoked = false;
+navigator.geolocation.getCurrentPosition(function(p) {
+    if (successCallbackInvoked) {
+        testFailed('Success callback invoked unexpectedly');
+        finishJSTest();
+    }
+    successCallbackInvoked = true;
+
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    debug('');
+    continueTest();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+});
+
+function continueTest() {
+    mock.setGeolocationPosition(++mockLatitude,
+                                ++mockLongitude,
+                                ++mockAccuracy);
+
     navigator.geolocation.getCurrentPosition(function(p) {
-        if (successCallbackInvoked) {
-            testFailed('Success callback invoked unexpectedly');
-            finishJSTest();
-        }
-        successCallbackInvoked = true;
-
         position = p;
         shouldBe('position.coords.latitude', 'mockLatitude');
         shouldBe('position.coords.longitude', 'mockLongitude');
         shouldBe('position.coords.accuracy', 'mockAccuracy');
-        debug('');
-        continueTest();
+        finishJSTest();
     }, function(e) {
         testFailed('Error callback invoked unexpectedly');
         finishJSTest();
     });
-
-    function continueTest() {
-        mock.setGeolocationPosition(++mockLatitude,
-                                    ++mockLongitude,
-                                    ++mockAccuracy);
-
-        navigator.geolocation.getCurrentPosition(function(p) {
-            position = p;
-            shouldBe('position.coords.latitude', 'mockLatitude');
-            shouldBe('position.coords.longitude', 'mockLongitude');
-            shouldBe('position.coords.accuracy', 'mockAccuracy');
-            finishJSTest();
-        }, function(e) {
-            testFailed('Error callback invoked unexpectedly');
-            finishJSTest();
-        });
-    }
-});
+}
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/remove-remote-context-in-error-callback-crash.html b/third_party/WebKit/LayoutTests/geolocation-api/remove-remote-context-in-error-callback-crash.html
index 2ffca6d0..d9e11a2 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/remove-remote-context-in-error-callback-crash.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/remove-remote-context-in-error-callback-crash.html
@@ -2,9 +2,7 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
 <script src="../resources/gc.js"></script>
-<script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
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..48b3c4bf 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
@@ -2,15 +2,16 @@
 <html>
   <head>
     <script src="../../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+    <script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
     <script src="geolocation-mock.js"></script>
     <script>
       function init() {
-          geolocationServiceMock.then(mock => {
-              mock.setGeolocationPermission(true);
-              mock.setGeolocationPosition(51.478, -0.166, 100);
-              window.parent.onIframeReady()
-          });
+          let mock = geolocationMock;
+          mock.setGeolocationPermission(true);
+          mock.setGeolocationPosition(51.478, -0.166, 100);
+          window.parent.onIframeReady()
       }
     </script>
   </head>
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..7a81d21 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js
+++ b/third_party/WebKit/LayoutTests/geolocation-api/resources/geolocation-mock.js
@@ -1,187 +1,177 @@
 /*
- * 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',
-    ['device/geolocation/public/interfaces/geolocation.mojom',
-     'device/geolocation/public/interfaces/geoposition.mojom',
-     'third_party/WebKit/public/platform/modules/permissions/permission.mojom',
-     'third_party/WebKit/public/platform/modules/permissions/permission_status.mojom',
-     'mojo/public/js/bindings',
-    ]).then(mojo => {
-  let [geolocation, geoposition, permission, permissionStatus, bindings] =
-      mojo.modules;
+class GeolocationMock {
+  constructor() {
+    this.geolocationInterceptor_ = new MojoInterfaceInterceptor(
+        device.mojom.Geolocation.name);
+    this.geolocationInterceptor_.oninterfacerequest =
+        e => this.connectGeolocation_(e.handle);
+    this.geolocationInterceptor_.start();
 
-  class GeolocationServiceMock {
-    constructor(interfaceProvider) {
-      interfaceProvider.addInterfaceOverrideForTesting(
-          geolocation.GeolocationService.name,
-          handle => this.connectGeolocation_(handle));
-
-      interfaceProvider.addInterfaceOverrideForTesting(
-          permission.PermissionService.name,
-          handle => this.connectPermission_(handle));
-
-      this.interfaceProvider_ = interfaceProvider;
-
-      /**
-       * The next geoposition to return in response to a queryNextPosition()
-       * call.
-      */
-      this.geoposition_ = null;
-
-      /**
-       * A pending request for permission awaiting a decision to be set via a
-       * setGeolocationPermission call.
-       *
-       * @type {?Function}
-       */
-      this.pendingPermissionRequest_ = null;
-
-      /**
-       * The status to respond to permission requests with. If set to ASK, then
-       * permission requests will block until setGeolocationPermission is called
-       * to allow or deny permission requests.
-       *
-       * @type {!permissionStatus.PermissionStatus}
-       */
-      this.permissionStatus_ = permissionStatus.PermissionStatus.ASK;
-      this.rejectPermissionConnections_ = false;
-      this.rejectGeolocationConnections_ = false;
-
-      this.geolocationBindingSet_ = new bindings.BindingSet(
-          geolocation.GeolocationService);
-      this.permissionBindingSet_ = new bindings.BindingSet(
-          permission.PermissionService);
-    }
-
-    connectGeolocation_(handle) {
-      if (this.rejectGeolocationConnections_) {
-        mojo.core.close(handle);
-        return;
-      }
-      this.geolocationBindingSet_.addBinding(this, handle);
-    }
-
-    connectPermission_(handle) {
-      if (this.rejectPermissionConnections_) {
-        mojo.core.close(handle);
-        return;
-      }
-      this.permissionBindingSet_.addBinding(this, handle);
-    }
-
-    setHighAccuracy(highAccuracy) {
-      // FIXME: We need to add some tests regarding "high accuracy" mode.
-      // See https://bugs.webkit.org/show_bug.cgi?id=49438
-    }
+    this.permissionInterceptor_ = new MojoInterfaceInterceptor(
+        blink.mojom.PermissionService.name);
+    this.permissionInterceptor_.oninterfacerequest =
+        e => this.connectPermission_(e.handle);
+    this.permissionInterceptor_.start();
 
     /**
-     * A mock implementation of GeolocationService.queryNextPosition(). This
-     * returns the position set by a call to setGeolocationPosition() or
-     * setGeolocationPositionUnavailableError().
-     */
-    queryNextPosition() {
-      if (!this.geoposition_) {
-        this.setGeolocationPositionUnavailableError(
-            'Test error: position not set before call to queryNextPosition()');
-      }
-      let geoposition = this.geoposition_;
-      this.geoposition_ = null;
-      return Promise.resolve({geoposition});
-    }
+     * The next geoposition to return in response to a queryNextPosition()
+     * call.
+    */
+    this.geoposition_ = null;
 
     /**
-     * Sets the position to return to the next queryNextPosition() call. If any
-     * queryNextPosition() requests are outstanding, they will all receive the
-     * position set by this call.
+     * A pending request for permission awaiting a decision to be set via a
+     * setGeolocationPermission call.
+     *
+     * @type {?Function}
      */
-    setGeolocationPosition(latitude, longitude, accuracy, altitude,
-                           altitudeAccuracy, heading, speed) {
-      this.geoposition_ = new geoposition.Geoposition();
-      this.geoposition_.latitude = latitude;
-      this.geoposition_.longitude = longitude;
-      this.geoposition_.accuracy = accuracy;
-      this.geoposition_.altitude = altitude;
-      this.geoposition_.altitude_accuracy = altitudeAccuracy;
-      this.geoposition_.heading = heading;
-      this.geoposition_.speed = speed;
-      this.geoposition_.timestamp = new Date().getTime() / 1000;
-      this.geoposition_.error_message = '';
-      this.geoposition_.valid = true;
-    }
+    this.pendingPermissionRequest_ = null;
 
     /**
-     * Sets the error message to return to the next queryNextPosition() call. If
-     * any queryNextPosition() requests are outstanding, they will all receive
-     * the error set by this call.
+     * The status to respond to permission requests with. If set to ASK, then
+     * permission requests will block until setGeolocationPermission is called
+     * to allow or deny permission requests.
+     *
+     * @type {!blink.mojom.PermissionStatus}
      */
-    setGeolocationPositionUnavailableError(message) {
-      this.geoposition_ = new geoposition.Geoposition();
-      this.geoposition_.valid = false;
-      this.geoposition_.error_message = message;
-      this.geoposition_.error_code =
-          geoposition.Geoposition.ErrorCode.POSITION_UNAVAILABLE;
-    }
+    this.permissionStatus_ = blink.mojom.PermissionStatus.ASK;
+    this.rejectPermissionConnections_ = false;
+    this.rejectGeolocationConnections_ = false;
 
-    /**
-     * Reject any connection requests for the permission service. This will
-     * trigger a connection error in the client.
-     */
-    rejectPermissionConnections() {
-      this.rejectPermissionConnections_ = true;
-    }
-
-    /**
-     * Reject any connection requests for the geolocation service. This will
-     * trigger a connection error in the client.
-     */
-    rejectGeolocationConnections() {
-      this.rejectGeolocationConnections_ = true;
-    }
-
-    /**
-     * A mock implementation of PermissionService.requestPermission(). This
-     * returns the result set by a call to setGeolocationPermission(), waiting
-     * for a call if necessary. Any permission request that is not for
-     * geolocation is always denied.
-     */
-    requestPermission(permissionDescriptor) {
-      if (permissionDescriptor.name != permission.PermissionName.GEOLOCATION)
-        return Promise.resolve(permissionStatus.PermissionStatus.DENIED);
-
-      return new Promise(resolve => {
-        if (this.pendingPermissionRequest_)
-          this.pendingPermissionRequest_(permissionStatus.PermissionStatus.ASK);
-        this.pendingPermissionRequest_ = resolve;
-        this.runPermissionCallback_();
-      });
-    }
-
-    runPermissionCallback_() {
-      if (this.permissionStatus_ == permissionStatus.PermissionStatus.ASK ||
-          !this.pendingPermissionRequest_)
-        return;
-
-      this.pendingPermissionRequest_({status: this.permissionStatus_});
-      this.permissionStatus_ = permissionStatus.PermissionStatus.ASK ;
-      this.pendingPermissionRequest_ = null;
-    }
-
-    /**
-     * Sets whether the next geolocation permission request should be allowed.
-     */
-    setGeolocationPermission(allowed) {
-      this.permissionStatus_ = allowed ?
-          permissionStatus.PermissionStatus.GRANTED :
-          permissionStatus.PermissionStatus.DENIED;
-      this.runPermissionCallback_();
-    }
-
+    this.geolocationBindingSet_ = new mojo.BindingSet(
+        device.mojom.Geolocation);
+    this.permissionBindingSet_ = new mojo.BindingSet(
+        blink.mojom.PermissionService);
   }
-  return new GeolocationServiceMock(mojo.frameInterfaces);
-});
+
+  connectGeolocation_(handle) {
+    if (this.rejectGeolocationConnections_) {
+      handle.close();
+      return;
+    }
+    this.geolocationBindingSet_.addBinding(this, handle);
+  }
+
+  connectPermission_(handle) {
+    if (this.rejectPermissionConnections_) {
+      handle.close();
+      return;
+    }
+    this.permissionBindingSet_.addBinding(this, handle);
+  }
+
+  setHighAccuracy(highAccuracy) {
+    // FIXME: We need to add some tests regarding "high accuracy" mode.
+    // See https://bugs.webkit.org/show_bug.cgi?id=49438
+  }
+
+  /**
+   * A mock implementation of GeolocationService.queryNextPosition(). This
+   * returns the position set by a call to setGeolocationPosition() or
+   * setGeolocationPositionUnavailableError().
+   */
+  queryNextPosition() {
+    if (!this.geoposition_) {
+      this.setGeolocationPositionUnavailableError(
+          'Test error: position not set before call to queryNextPosition()');
+    }
+    let geoposition = this.geoposition_;
+    this.geoposition_ = null;
+    return Promise.resolve({geoposition});
+  }
+
+  /**
+   * Sets the position to return to the next queryNextPosition() call. If any
+   * queryNextPosition() requests are outstanding, they will all receive the
+   * position set by this call.
+   */
+  setGeolocationPosition(latitude, longitude, accuracy, altitude,
+                         altitudeAccuracy, heading, speed) {
+    this.geoposition_ = new device.mojom.Geoposition();
+    this.geoposition_.latitude = latitude;
+    this.geoposition_.longitude = longitude;
+    this.geoposition_.accuracy = accuracy;
+    this.geoposition_.altitude = altitude;
+    this.geoposition_.altitudeAccuracy = altitudeAccuracy;
+    this.geoposition_.heading = heading;
+    this.geoposition_.speed = speed;
+    this.geoposition_.timestamp = new Date().getTime() / 1000;
+    this.geoposition_.errorMessage = '';
+    this.geoposition_.valid = true;
+  }
+
+  /**
+   * Sets the error message to return to the next queryNextPosition() call. If
+   * any queryNextPosition() requests are outstanding, they will all receive
+   * the error set by this call.
+   */
+  setGeolocationPositionUnavailableError(message) {
+    this.geoposition_ = new device.mojom.Geoposition();
+    this.geoposition_.valid = false;
+    this.geoposition_.errorMessage = message;
+    this.geoposition_.errorCode =
+        device.mojom.Geoposition.ErrorCode.POSITION_UNAVAILABLE;
+  }
+
+  /**
+   * Reject any connection requests for the permission service. This will
+   * trigger a connection error in the client.
+   */
+  rejectPermissionConnections() {
+    this.rejectPermissionConnections_ = true;
+  }
+
+  /**
+   * Reject any connection requests for the geolocation service. This will
+   * trigger a connection error in the client.
+   */
+  rejectGeolocationConnections() {
+    this.rejectGeolocationConnections_ = true;
+  }
+
+  /**
+   * A mock implementation of PermissionService.requestPermission(). This
+   * returns the result set by a call to setGeolocationPermission(), waiting
+   * for a call if necessary. Any permission request that is not for
+   * geolocation is always denied.
+   */
+  requestPermission(permissionDescriptor) {
+    if (permissionDescriptor.name != blink.mojom.PermissionName.GEOLOCATION)
+      return Promise.resolve(blink.mojom.PermissionStatus.DENIED);
+
+    return new Promise(resolve => {
+      if (this.pendingPermissionRequest_)
+        this.pendingPermissionRequest_(blink.mojom.PermissionStatus.ASK);
+      this.pendingPermissionRequest_ = resolve;
+      this.runPermissionCallback_();
+    });
+  }
+
+  runPermissionCallback_() {
+    if (this.permissionStatus_ == blink.mojom.PermissionStatus.ASK ||
+        !this.pendingPermissionRequest_)
+      return;
+
+    this.pendingPermissionRequest_({status: this.permissionStatus_});
+    this.permissionStatus_ = blink.mojom.PermissionStatus.ASK;
+    this.pendingPermissionRequest_ = null;
+  }
+
+  /**
+   * Sets whether the next geolocation permission request should be allowed.
+   */
+  setGeolocationPermission(allowed) {
+    this.permissionStatus_ = allowed ?
+        blink.mojom.PermissionStatus.GRANTED :
+        blink.mojom.PermissionStatus.DENIED;
+    this.runPermissionCallback_();
+  }
+}
+
+let geolocationMock = new GeolocationMock();
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..d520c95 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
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 <html>
   <head>
-    <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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+    <script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
     <script src="geolocation-mock.js"></script>
     <script>
       function init() {
-          geolocationServiceMock.then(mock => {
-              mock.setGeolocationPermission(false);
-              window.parent.onIframeReady()
-          });
+          geolocationMock.setGeolocationPermission(false);
+          window.parent.onIframeReady();
       }
     </script>
   </head>
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..419bb85 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
@@ -1,4 +1,6 @@
-<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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="geolocation-mock.js"></script>
 <script>
 var mockLatitude = 51.478;
@@ -6,12 +8,11 @@
 var mockAccuracy = 100.0;
 
 function loadNext() {
-    geolocationServiceMock.then(mock => {
-        mock.setGeolocationPermission(true);
-        mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+    let mock = geolocationMock;
+    mock.setGeolocationPermission(true);
+    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-        navigator.geolocation.watchPosition(window.opener.gotPosition);
-    });
+    navigator.geolocation.watchPosition(window.opener.gotPosition);
 }
 </script>
 <body onload="loadNext()"></body>
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..7d29e9a 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/success-clear-watch.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -13,19 +15,18 @@
 var mockLongitude = -0.166;
 var mockAccuracy = 100;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    var watchId = navigator.geolocation.watchPosition(function() {
-        navigator.geolocation.clearWatch(watchId);
-        finishJSTest();
-    }, function(e) {
-        navigator.geolocation.clearWatch(watchId);
-        finishJSTest();
-    });
+var watchId = navigator.geolocation.watchPosition(function() {
+    navigator.geolocation.clearWatch(watchId);
+    finishJSTest();
+}, function(e) {
+    navigator.geolocation.clearWatch(watchId);
+    finishJSTest();
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/success.html b/third_party/WebKit/LayoutTests/geolocation-api/success.html
index 5c442ea..369baf9 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/success.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/success.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,22 +17,21 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
-        finishJSTest();
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    finishJSTest();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
 window.jsTestIsAsync = true;
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..4551654 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-clear-watch.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,21 +13,20 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    var watchId = navigator.geolocation.watchPosition(function() {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        error = e;
-        shouldBe('error.code', 'error.TIMEOUT');
-        shouldBe('error.message', '"Timeout expired"');
-        navigator.geolocation.clearWatch(watchId);
-        window.setTimeout(finishJSTest, 0);
-    }, {
-        timeout: 0
-    });
+var watchId = navigator.geolocation.watchPosition(function() {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.TIMEOUT');
+    shouldBe('error.message', '"Timeout expired"');
+    navigator.geolocation.clearWatch(watchId);
+    window.setTimeout(finishJSTest, 0);
+}, {
+    timeout: 0
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
index c054ddc..bb819f7 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-negative.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,20 +13,19 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
+let mock = geolocationMock;
+mock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        error = e;
-        shouldBe('error.code', 'error.TIMEOUT');
-        shouldBe('error.message', '"Timeout expired"');
-        finishJSTest();
-    }, {
-        timeout: -1000
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.TIMEOUT');
+    shouldBe('error.message', '"Timeout expired"');
+    finishJSTest();
+}, {
+    timeout: -1000
 });
 
 window.jsTestIsAsync = true;
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..301b433 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
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,24 +17,23 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
-        finishJSTest();
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    }, {
-        timeout: 4294967296
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    finishJSTest();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+}, {
+    timeout: 4294967296
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
index 25b6322e..5b02c10 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout-zero.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -11,20 +13,18 @@
 
 var error;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
+geolocationMock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        testFailed('Success callback invoked unexpectedly');
-        finishJSTest();
-    }, function(e) {
-        error = e;
-        shouldBe('error.code', 'error.TIMEOUT');
-        shouldBe('error.message', '"Timeout expired"');
-        finishJSTest();
-    }, {
-        timeout: 0
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    testFailed('Success callback invoked unexpectedly');
+    finishJSTest();
+}, function(e) {
+    error = e;
+    shouldBe('error.code', 'error.TIMEOUT');
+    shouldBe('error.message', '"Timeout expired"');
+    finishJSTest();
+}, {
+    timeout: 0
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timeout.html b/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
index 66f1fc8..65265cb 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timeout.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -15,24 +17,23 @@
 
 var position;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude,
-                                mockLongitude,
-                                mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude,
+                            mockLongitude,
+                            mockAccuracy);
 
-    navigator.geolocation.getCurrentPosition(function(p) {
-        position = p;
-        shouldBe('position.coords.latitude', 'mockLatitude');
-        shouldBe('position.coords.longitude', 'mockLongitude');
-        shouldBe('position.coords.accuracy', 'mockAccuracy');
-        finishJSTest();
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    }, {
-        timeout: 1000
-    });
+navigator.geolocation.getCurrentPosition(function(p) {
+    position = p;
+    shouldBe('position.coords.latitude', 'mockLatitude');
+    shouldBe('position.coords.longitude', 'mockLongitude');
+    shouldBe('position.coords.accuracy', 'mockAccuracy');
+    finishJSTest();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
+}, {
+    timeout: 1000
 });
 
 window.jsTestIsAsync = true;
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html b/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
index 9688561..b27f44af 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/timestamp.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -18,27 +20,27 @@
 var t = null;
 var then = null;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-    function checkPosition(p) {
-        t = p.timestamp;
-        var d = new Date();
-        then = d.getTime();
-        shouldBeTrue('t != 0');
-        shouldBeTrue('then != 0');
-        shouldBeTrue('now - 1 <= t'); // Avoid rounding errors
-        if (now - 1 > t) {
-            debug("  now - 1 = " + (now-1));
-            debug("  t = " + t);
-        }
-        shouldBeTrue('t <= then + 1'); // Avoid rounding errors
-        finishJSTest();
+function checkPosition(p) {
+    t = p.timestamp;
+    var d = new Date();
+    then = d.getTime();
+    shouldBeTrue('t != 0');
+    shouldBeTrue('then != 0');
+    shouldBeTrue('now - 1 <= t'); // Avoid rounding errors
+    if (now - 1 > t) {
+        debug("  now - 1 = " + (now-1));
+        debug("  t = " + t);
     }
+    shouldBeTrue('t <= then + 1'); // Avoid rounding errors
+    finishJSTest();
+}
 
-    navigator.geolocation.getCurrentPosition(checkPosition);
-});
+navigator.geolocation.getCurrentPosition(checkPosition);
+
 window.jsTestIsAsync = true;
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/watch.html b/third_party/WebKit/LayoutTests/geolocation-api/watch.html
index 9e8df07..cbd2cd5 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watch.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watch.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -33,40 +35,39 @@
     debug('');
 }
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-    var state = 0;
-    navigator.geolocation.watchPosition(function(p) {
-        switch (state++) {
-            case 0:
-                checkPosition(p);
-                mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
-                break;
-            case 1:
-                checkPosition(p);
-                mock.setGeolocationPositionUnavailableError(mockMessage);
-                break;
-            case 3:
-                checkPosition(p);
-                finishJSTest();
-                break;
-            default:
-                testFailed('Success callback invoked unexpectedly');
-                finishJSTest();
-        }
-    }, function(e) {
-        switch (state++) {
-            case 2:
-                checkError(e);
-                mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
-                break;
-            default:
-                testFailed('Error callback invoked unexpectedly');
-                finishJSTest();
-        }
-    });
+var state = 0;
+navigator.geolocation.watchPosition(function(p) {
+    switch (state++) {
+        case 0:
+            checkPosition(p);
+            mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
+            break;
+        case 1:
+            checkPosition(p);
+            mock.setGeolocationPositionUnavailableError(mockMessage);
+            break;
+        case 3:
+            checkPosition(p);
+            finishJSTest();
+            break;
+        default:
+            testFailed('Success callback invoked unexpectedly');
+            finishJSTest();
+    }
+}, function(e) {
+    switch (state++) {
+        case 2:
+            checkError(e);
+            mock.setGeolocationPosition(++mockLatitude, ++mockLongitude, ++mockAccuracy);
+            break;
+        default:
+            testFailed('Error callback invoked unexpectedly');
+            finishJSTest();
+    }
 });
 
 window.jsTestIsAsync = true;
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..8bb6b315c 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-page-visibility.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -17,71 +19,70 @@
 var error;
 var isPageVisible = true;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
 
-    debug("* Page is visible");
+debug("* Page is visible");
 
-    var mockLatitude = 51.478;
-    var mockLongitude = -0.166;
-    var mockAccuracy = 100.0;
+var mockLatitude = 51.478;
+var mockLongitude = -0.166;
+var mockAccuracy = 100.0;
 
-    function updatePosition() {
-        if (!window.testRunner)
-            return;
-        ++mockLatitude;
-        ++mockLongitude;
-        mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
-        debug('device moved to (' + mockLatitude + ', ' + mockLongitude + ')');
+function updatePosition() {
+    if (!window.testRunner)
+        return;
+    ++mockLatitude;
+    ++mockLongitude;
+    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+    debug('device moved to (' + mockLatitude + ', ' + mockLongitude + ')');
+}
+
+updatePosition();
+
+var state = 0;
+
+function checkPosition(p) {
+    position = p;
+    shouldBe('position.coords.latitude', '' + mockLatitude);
+    shouldBe('position.coords.longitude', '' + mockLongitude);
+    debug('');
+}
+
+function showPageAndUpdatePosition() {
+    shouldBeFalse('isPageVisible');
+    debug('');
+    state++;
+    if (window.testRunner) {
+        debug("*Showing page");
+        testRunner.setPageVisibility("visible");
+        isPageVisible = true;
     }
-
     updatePosition();
+}
 
-    var state = 0;
-
-    function checkPosition(p) {
-        position = p;
-        shouldBe('position.coords.latitude', '' + mockLatitude);
-        shouldBe('position.coords.longitude', '' + mockLongitude);
-        debug('');
-    }
-
-    function showPageAndUpdatePosition() {
-        shouldBeFalse('isPageVisible');
-        debug('');
-        state++;
-        if (window.testRunner) {
-            debug("*Showing page");
-            testRunner.setPageVisibility("visible");
-            isPageVisible = true;
-        }
-        updatePosition();
-    }
-
-    navigator.geolocation.watchPosition(function(p) {
-        debug("Page is notified of the position change");
-        shouldBeTrue('isPageVisible');
-        state++;
-        checkPosition(p);
-        switch(state) {
-            case 2: {
-                if (window.testRunner) {
-                    debug("* Hiding page");
-                    testRunner.setPageVisibility("hidden");
-                    isPageVisible = false;
-                }
-                setTimeout(showPageAndUpdatePosition, 100);
-                break;
+navigator.geolocation.watchPosition(function(p) {
+    debug("Page is notified of the position change");
+    shouldBeTrue('isPageVisible');
+    state++;
+    checkPosition(p);
+    switch(state) {
+        case 2: {
+            if (window.testRunner) {
+                debug("* Hiding page");
+                testRunner.setPageVisibility("hidden");
+                isPageVisible = false;
             }
-            case 4:
-                finishJSTest();
-                return;
+            setTimeout(showPageAndUpdatePosition, 100);
+            break;
         }
-        updatePosition();
-    }, function(e) {
-        testFailed('Error callback invoked unexpectedly');
-        finishJSTest();
-    });
+        case 4:
+            finishJSTest();
+            return;
+    }
+    updatePosition();
+}, function(e) {
+    testFailed('Error callback invoked unexpectedly');
+    finishJSTest();
 });
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
index 5dd5942..6ef8235 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/watchPosition-unique.html
@@ -2,7 +2,9 @@
 <html>
 <head>
 <script src="../resources/js-test.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/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
@@ -14,21 +16,19 @@
 var watchID2;
 var watchID3;
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPosition(51.478, -0.166, 100.0);
+geolocationMock.setGeolocationPosition(51.478, -0.166, 100.0);
 
-    watchID1 = navigator.geolocation.watchPosition(function() { });
-    watchID2 = navigator.geolocation.watchPosition(function() { });
-    watchID3 = navigator.geolocation.watchPosition(function() { });
+watchID1 = navigator.geolocation.watchPosition(function() { });
+watchID2 = navigator.geolocation.watchPosition(function() { });
+watchID3 = navigator.geolocation.watchPosition(function() { });
 
-    shouldBeTrue("watchID1 > 0");
-    shouldBeTrue("watchID2 > 0");
-    shouldBeTrue("watchID3 > 0");
-    shouldBeTrue("watchID1 !== watchID2");
-    shouldBeTrue("watchID1 !== watchID3");
-    shouldBeTrue("watchID2 !== watchID3");
-    finishJSTest();
-});
+shouldBeTrue("watchID1 > 0");
+shouldBeTrue("watchID2 > 0");
+shouldBeTrue("watchID3 > 0");
+shouldBeTrue("watchID1 !== watchID2");
+shouldBeTrue("watchID1 !== watchID3");
+shouldBeTrue("watchID2 !== watchID3");
+finishJSTest();
 
 window.jsTestIsAsync = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/geolocation-api/window-close-crash.html b/third_party/WebKit/LayoutTests/geolocation-api/window-close-crash.html
index a27b7b5..f5f9662 100644
--- a/third_party/WebKit/LayoutTests/geolocation-api/window-close-crash.html
+++ b/third_party/WebKit/LayoutTests/geolocation-api/window-close-crash.html
@@ -2,8 +2,6 @@
 <html>
 <head>
 <script src="../resources/js-test.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
-<script src="resources/geolocation-mock.js"></script>
 </head>
 <body>
 <script>
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..5564b5b6 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
@@ -1,6 +1,9 @@
 <!DOCTYPE html>
 <title>Geolocation On A Secure Origin</title>
-<script src="/js-test-resources/mojo-helpers.js"></script>
+
+<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="/gen/device/geolocation/public/interfaces/geolocation.mojom.js"></script>
+<script src="/gen/third_party/WebKit/public/platform/modules/permissions/permission.mojom.js"></script>
 <script src="/geolocation-api/js-test-resources/geolocation-mock.js"></script>
 <script>
 var mockLatitude = 51.478;
@@ -10,16 +13,15 @@
 if (!window.mojo)
     console.error('This test can not run without mojo');
 
-geolocationServiceMock.then(mock => {
-    mock.setGeolocationPermission(true);
-    mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
+let mock = geolocationMock;
+mock.setGeolocationPermission(true);
+mock.setGeolocationPosition(mockLatitude, mockLongitude, mockAccuracy);
 
-    navigator.geolocation.getCurrentPosition(
-        function () {
-            window.parent.postMessage({ success: true }, "*");
-        },
-        function (error) {
-            window.parent.postMessage({ message: error.message }, "*");
-        }, { maximumAge: 10000 });
-});
+navigator.geolocation.getCurrentPosition(
+    function () {
+        window.parent.postMessage({ success: true }, "*");
+    },
+    function (error) {
+        window.parent.postMessage({ message: error.message }, "*");
+    }, { maximumAge: 10000 });
 </script>
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 6fc93be9..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..f257db6a 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/paint/invalidation/repaint-subrect-grid-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-subrect-grid-expected.png
index 43f29cb..b71ae8a3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-subrect-grid-expected.png
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-subrect-grid-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/animations/keyframe-multiple-timing-functions-transform-expected.png b/third_party/WebKit/LayoutTests/platform/linux/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/animations/keyframe-multiple-timing-functions-transform-expected.png
rename to third_party/WebKit/LayoutTests/platform/linux/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/images/direct-image-background-color-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/images/direct-image-background-color-expected.png
index e8ea60c..8b07da6a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/images/direct-image-background-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/images/direct-image-background-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png
deleted file mode 100644
index 0f98aad..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/img-layer-object-fit-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-added-filters-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-added-filters-expected.png
index ae5f6f7..c8800e2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-added-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-added-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-removed-filters-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-removed-filters-expected.png
index d74c112..b6ed986a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-removed-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/mask-with-removed-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-02-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-02-d-g-expected.png
index 0a321438..0a02aa13 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-02-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-02-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-03-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-03-b-g-expected.png
index f70970e..969eed5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-03-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-03-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-ln-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
index 0fc1950..ff27ddd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-l-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
index d2149ec1..a28dea4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-r-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
index acc96b7b9..831cec8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
index eff9bb3..76a467a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
index 1533760..47ec11c5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t1004-c5524-width-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t1004-c5524-width-00-b-g-expected.png
index c84259e..8afafad4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t1004-c5524-width-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t1004-c5524-width-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/background/background-large-position-and-size-remains-stable-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/background/background-large-position-and-size-remains-stable-expected.png
deleted file mode 100644
index 2861135..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/css3/background/background-large-position-and-size-remains-stable-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
index f40f82e..e0fc1326 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/size/contain-and-cover-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/size/contain-and-cover-expected.png
new file mode 100644
index 0000000..dcba2fd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/size/contain-and-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-expected.png
index 90c80758..e020d0c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-outset-expected.png
index 20e55d9..10227c4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-outset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/block-mask-overlay-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-01-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-01-expected.png
deleted file mode 100644
index 455f42d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-01-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-border-radius-expected.png
index 4509b25..e95ab05 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-longhand-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-longhand-expected.png
deleted file mode 100644
index 455f42d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-longhand-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-massive-scale-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-massive-scale-expected.png
deleted file mode 100644
index 8c751f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-massive-scale-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-expected.png
deleted file mode 100644
index 2171979a..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-in-shorthand-expected.png
deleted file mode 100644
index 2171979a..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-outset-in-shorthand-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-repeat-expected.png
deleted file mode 100644
index 455f42d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-repeat-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-rotate-transform-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-rotate-transform-expected.png
deleted file mode 100644
index 0d2ed27..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-rotate-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scale-transform-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scale-transform-expected.png
deleted file mode 100644
index d59f93ec..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scale-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scaled-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scaled-expected.png
index 61fc390..37b528b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scaled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scaled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scrambled-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scrambled-expected.png
deleted file mode 100644
index 455f42d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-scrambled-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png
deleted file mode 100644
index 67937608..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-side-reduction-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-slices-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-slices-expected.png
deleted file mode 100644
index cf38daa..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-slices-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-source-expected.png
deleted file mode 100644
index 455f42d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-image-source-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-expected.png
index 22192e5..8ba5ae4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/inline-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/scaled-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/scaled-border-image-expected.png
index c339b47..e44ad85 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/scaled-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/scaled-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index d8769da..ddbf0ff1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-landscape-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-landscape-expected.png
index cbeebce3..e1a9ecf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-landscape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-portrait-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-portrait-expected.png
index 79fd376d..a336166 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-portrait-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/hidpi/broken-image-with-size-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/hidpi/broken-image-with-size-hidpi-expected.png
index ab2ade1..e48a88e1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/hidpi/broken-image-with-size-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/hidpi/broken-image-with-size-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/001-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/001-expected.png
index 4e832ad..c9750fa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/002-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/002-expected.png
index 1880b75..1e97d9cb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/003-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/003-expected.png
index 1880b75..1e97d9cb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/absolute-image-sizing-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/absolute-image-sizing-expected.png
index ab404ac..f3f70e4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/absolute-image-sizing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/absolute-image-sizing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index 947995f..d05cee8f1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/imagemap-focus-ring-zero-outline-width-expected.png
index b9a56d18..4f1129f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png
deleted file mode 100644
index 0a10bdc0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/media/video-poster-scale-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
index fe57f0a..197c24f26 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 7716315..c88611c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
index fe1c0f0..50c2460 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
index 8948dd12..156279d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
index 21e8c18..01d2527d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
index 2a6e286..d077923 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
index 15422fe..1dfe520 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
index 2c68dd2..ded86dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
index bd72996..90c6ef6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
index 2c68dd2..ded86dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
index bd72996..90c6ef6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
index bd72996..90c6ef6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
index 2c68dd2..ded86dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
index 2c68dd2..ded86dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
index bd72996..90c6ef6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
index bd72996..90c6ef6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
index 2c68dd2..ded86dc 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-no-markup-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-no-markup-expected.png
index 86e1c88c..fc0efe2c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-no-markup-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-anchor-no-markup-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
index 8948dd12..156279d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
index 7c30311..5577511 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
index 2a6e286..d077923 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
index 6f66f19..c8ac1596 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
index c052f72..1ab8a84 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
index bfd2bed..b562eab 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
index 2062caa0..13ecf118 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
index 2062caa0..13ecf118 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
index ca662ef..1e95a0e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
index 19b6a72..0baee599 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
index 19b6a72..0baee599 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
index c26a1fb..0958e54 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
index 3b72664..afbe241 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
index 3b72664..afbe241 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
index 8724709..67373b3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
index 8724709..67373b3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
index b7fd917d..fc6768d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
index b7fd917d..fc6768d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
index 8c4910ef..8701c0e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-ltr-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-ltr-expected.png
index bb6ee8ce..32258f8e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-ltr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-ltr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-rtl-expected.png
index 5e8e22c..51a98fde 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-I18N/tspan-direction-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index 65e2621..8765d73 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index 6b14ba32..38b8798 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index e4f62ec..d37d17a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
index a3b2bd0..fd57970c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-image/image-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-image/image-preserveAspectRatio-all-expected.png
index 29fef3e..5e28f16 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-image/image-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-image/image-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
index e1dca62..a1a8854 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png
index e3e496e..4c5450f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/hixie/perf/004-expected.png
Binary files differ
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/linux/tables/mozilla/bugs/bug137388-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug137388-2-expected.png
index e543c7d..42593bb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug137388-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug137388-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug15544-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug15544-expected.png
index de43df8..cacc4aa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug15544-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug15544-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug23235-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug23235-expected.png
index ecf2c8c..ce6d158f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug23235-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug23235-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug86708-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug86708-expected.png
index 29ef5d25a..0e08586f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug86708-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/bugs/bug86708-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_baseline-expected.png
index ce5c801..5ffd73b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_bottom-expected.png
index 91112e4..c142c37 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_middle-expected.png
index 6eb456b..ce9007e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_top-expected.png
index 4845db1d..40e02ed3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tbody_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_baseline-expected.png
index 5589f7a3..e04ae5f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_bottom-expected.png
index e8a288b..2d257c56 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_middle-expected.png
index c5c74827..1fc8da55 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_top-expected.png
index c5182bb..0e947791 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/td_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
index 0b9a9cd..560b8c9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
index b890732..5f18ce1e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_middle-expected.png
index 8badd3f..c62fe6c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_top-expected.png
index cbd8e28..a45d5e88 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tfoot_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_baseline-expected.png
index c05cb53f..ace214b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_bottom-expected.png
index c2c602a..9dc61a72 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_middle-expected.png
index 97fc585..d552ffe 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_top-expected.png
index 5baed82..71ef674 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/th_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_baseline-expected.png
index ca7e55f..feb807f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_bottom-expected.png
index 8627f70..4243f465 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_middle-expected.png
index 29a617c..41bb2c5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_top-expected.png
index ab956e77..ad0eed1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/thead_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_baseline-expected.png
index b7198bf5..9b4eb00 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_bottom-expected.png
index cf311ce..ed123b6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_middle-expected.png
index 30ef6260..435ec627 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_top-expected.png
index 1a6f512..188444d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla/marvin/tr_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/97619-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/97619-expected.png
index 1dc6b07..98d97af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/97619-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/97619-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug1647-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug1647-expected.png
index bc2a1bd..0afcd96 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug1647-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/bugs/bug1647-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index d8769da..ddbf0ff1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
index 18ad233..51f8501 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index 62275dc..f465da69 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 2a31895..be38e06a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
index e897dd9c..159962c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index fe1c0f0..50c2460 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
index fe1c0f0..50c2460 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug23235-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug23235-expected.png
index ef96757..dd2b81f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug23235-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla/bugs/bug23235-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/borders/inline-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/borders/inline-mask-overlay-image-expected.png
index dbc8a65..00272ef 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/borders/inline-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/borders/inline-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index 98cecf7..38cce9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-poster-scale-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-poster-scale-expected.png
index acafb2d0..f092fd2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-poster-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-poster-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index f066428e..2faa9cd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug137388-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug137388-2-expected.png
index 1055dbe..99d655f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug137388-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla/bugs/bug137388-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/animations/keyframe-multiple-timing-functions-transform-expected.png b/third_party/WebKit/LayoutTests/platform/mac/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/animations/keyframe-multiple-timing-functions-transform-expected.png
rename to third_party/WebKit/LayoutTests/platform/mac/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/images/direct-image-background-color-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/images/direct-image-background-color-expected.png
index 0a7b3b8..6b5b049 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/images/direct-image-background-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/images/direct-image-background-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/img-layer-object-fit-expected.png
new file mode 100644
index 0000000..2cb25f9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/img-layer-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-added-filters-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-added-filters-expected.png
index cbbb920..98fe5684 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-added-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-added-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-removed-filters-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-removed-filters-expected.png
index 0481bdbb..b42650f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-removed-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/mask-with-removed-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-02-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-02-d-g-expected.png
index 227305b..6267f94 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-02-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-02-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-03-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-03-b-g-expected.png
index b4e0bb4..c82291b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-03-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-03-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-ln-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
index a68be26..25d42b47 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-l-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
index fbd0652..7fe8d32 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-r-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
index a457d573..056bde7f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
index 712f5b7..95e637fa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
index 46f72e05..a148045 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t1004-c5524-width-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t1004-c5524-width-00-b-g-expected.png
index adeceb7..e92b2a3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css2.1/t1004-c5524-width-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css2.1/t1004-c5524-width-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/background/background-large-position-and-size-remains-stable-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/background/background-large-position-and-size-remains-stable-expected.png
new file mode 100644
index 0000000..9f7d79d4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/background/background-large-position-and-size-remains-stable-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
index cafcaa6..5b9131f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-expected.png
index d92674f..a2941368 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-outset-expected.png
index a8b1aa15..de8de738 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-outset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/block-mask-overlay-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-01-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-01-expected.png
new file mode 100644
index 0000000..28442280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-01-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-border-radius-expected.png
index 86df473..92a5ffa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-longhand-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-longhand-expected.png
new file mode 100644
index 0000000..28442280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-longhand-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-massive-scale-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-massive-scale-expected.png
new file mode 100644
index 0000000..9db8a87
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-massive-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-expected.png
new file mode 100644
index 0000000..1b66a607
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png
new file mode 100644
index 0000000..1b66a607
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-outset-in-shorthand-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-expected.png
new file mode 100644
index 0000000..28442280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-round-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-round-expected.png
index de75df1..8102267 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-round-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-repeat-round-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-rotate-transform-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-rotate-transform-expected.png
new file mode 100644
index 0000000..2a8f72d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-rotate-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scale-transform-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scale-transform-expected.png
new file mode 100644
index 0000000..9ba5be3e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scale-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scaled-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scaled-expected.png
index e716b6d3..391f008 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scaled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scaled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png
new file mode 100644
index 0000000..28442280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-side-reduction-expected.png
new file mode 100644
index 0000000..5bc68a07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-side-reduction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-slices-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-slices-expected.png
new file mode 100644
index 0000000..849500b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-slices-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-source-expected.png
new file mode 100644
index 0000000..28442280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/inline-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/inline-mask-overlay-image-expected.png
index c3cb807..55de7565 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/inline-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/inline-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/scaled-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/scaled-border-image-expected.png
index 4476876..7bc1bf66 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/scaled-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/scaled-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index f25acba..ad7239b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
index 998a8ae3..b709b30 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
index 5033d1c..9cde360 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/hidpi/broken-image-with-size-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/hidpi/broken-image-with-size-hidpi-expected.png
index f2e6872..33c113a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/hidpi/broken-image-with-size-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/hidpi/broken-image-with-size-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/001-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/001-expected.png
index 7736082..6a6c328 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/002-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/002-expected.png
index 18ee495f..771f24c6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/003-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/003-expected.png
index 18ee495f..771f24c6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/absolute-image-sizing-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/absolute-image-sizing-expected.png
index 007064a..470e00c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/absolute-image-sizing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/absolute-image-sizing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index fa1fd8a..4792f31d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-image-source-expected.png
index d6c4262e..28442280 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/imagemap-focus-ring-zero-outline-width-expected.png
index 83cfa730..b3a8d10 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-poster-scale-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-poster-scale-expected.png
index e76254b..266d6a7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/video-poster-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-poster-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
index ac4d7260..264692c9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 4337e0be..9194b38 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
index 856fcb6..ef18458 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
index ec603600..c17ba66 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
index 09424d68..9534d9a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
index dcb73c9..c6b9cb30 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
index c31571c..2134d843 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
index f9aaaf6..78598918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
index 65c6223..a205981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
index f9aaaf6..78598918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
index 65c6223..a205981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
index 65c6223..a205981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
index f9aaaf6..78598918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
index f9aaaf6..78598918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
index 65c6223..a205981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
index 65c6223..a205981 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
index f9aaaf6..78598918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-no-markup-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-no-markup-expected.png
index deca1ca5..30773b1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-no-markup-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-anchor-no-markup-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
index ec603600..c17ba66 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
index ba6963b0..1eaf8cc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
index dcb73c9..c6b9cb30 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
index 2c821d2c..54510ff1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
index 95adcf8c..8fead64d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
index 4758132..4c92169 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
index a1164fc7..3406b55b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
index a1164fc7..3406b55b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
index 7bd3156..3b2e3bed 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
index cc8ae1d..1ba589e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
index cc8ae1d..1ba589e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
index c6abcd217..ce31e48 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
index bc25cb7..3c16e67 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
index bc25cb7..3c16e67 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
index bb1cc586..37fa58f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
index bb1cc586..37fa58f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
index cc5a6f50..0088d17 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
index cc5a6f50..0088d17 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
index f7613449..162e711 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-ltr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-ltr-expected.png
index 9081440..17f391e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-ltr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-ltr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-rtl-expected.png
index 2063933..f9e9857 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-I18N/tspan-direction-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index b3805ec..e7949ea 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index ad5a32ef..eea93db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index 0dd9d7d..9ab918b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-image/image-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-image/image-preserveAspectRatio-all-expected.png
index 29fef3e..5e28f16 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-image/image-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-image/image-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
index 43299975..d51eb86 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
index 7c26852e..46b1b9d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/perf/004-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug137388-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug137388-2-expected.png
index c61bae1d..b0b3ca97 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug137388-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug137388-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug15544-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug15544-expected.png
index 6b87d3d..1846a40 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug15544-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug15544-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug23235-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug23235-expected.png
index 729f5d1..9191e5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug23235-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug23235-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug86708-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug86708-expected.png
index ef117ff..d98167a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug86708-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/bugs/bug86708-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_baseline-expected.png
index 9eb51c3c..ed41b5f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_bottom-expected.png
index 24295db6..4fb59ed 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_middle-expected.png
index 3724391..0688e07 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_top-expected.png
index 95604316..307a72c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tbody_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_baseline-expected.png
index ec27a0d..5799506 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_bottom-expected.png
index 2b038445..5d286650 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_middle-expected.png
index 34c5590b..7c3f50c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_top-expected.png
index a26b025..9d412b48 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/td_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
index bd8a146..03bce3b3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
index 94545919..c6c7da5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_middle-expected.png
index eb9c19d..baebdcc7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_top-expected.png
index 20c4f73d..34ebb7a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tfoot_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_baseline-expected.png
index 9e57a52..39d20f6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_bottom-expected.png
index 19545f7f..b122cba1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_middle-expected.png
index d759ac0f..02c9443 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_top-expected.png
index 9d0ba6e..c69b83d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/th_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_baseline-expected.png
index dc3c0645..830ac00 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_bottom-expected.png
index ff79ada9..005a2c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_middle-expected.png
index 89057c7..f7ba07b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_top-expected.png
index bb0b4b1..41365a31 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/thead_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_baseline-expected.png
index 9eaf8bbd..25541c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_bottom-expected.png
index 79cf726d..b1cadec 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_middle-expected.png
index ac3f4807..a6dfc1a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_top-expected.png
index 3b6e0e6..44471a8b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla/marvin/tr_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/97619-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/97619-expected.png
index dafdaa0..9c022d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/97619-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/97619-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug1647-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug1647-expected.png
index c02b7a3d..d85081c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug1647-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug1647-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index f25acba..ad7239b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
index 1ebb268..4f80329 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index f61a359..5a91180e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 7acdfe7..d523c07 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
index e897dd9c..159962c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index 856fcb6..ef18458 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
index 856fcb6..ef18458 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
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/animations/keyframe-multiple-timing-functions-transform-expected.png b/third_party/WebKit/LayoutTests/platform/win/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/win/animations/keyframe-multiple-timing-functions-transform-expected.png
rename to third_party/WebKit/LayoutTests/platform/win/animations/timing/keyframe-multiple-timing-functions-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/images/direct-image-background-color-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/images/direct-image-background-color-expected.png
index 7d0e22d7..921a0c31 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/images/direct-image-background-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/images/direct-image-background-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/img-layer-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/img-layer-object-fit-expected.png
index 0f98aad..6bb925c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/img-layer-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/img-layer-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-added-filters-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-added-filters-expected.png
index 0f3703a5..9afb2288 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-added-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-added-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-removed-filters-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-removed-filters-expected.png
index a469aba..699f209 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-removed-filters-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/mask-with-removed-filters-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-02-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-02-d-g-expected.png
index b96b319..9635d88 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-02-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-02-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-03-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-03-b-g-expected.png
index d2e6920..e3e2f5e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-03-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-03-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-ln-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
index be07d60..c7cbfba 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c414-flt-ln-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-l-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
index 9d3636e55..f7e8b264 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-l-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-r-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
index 8ae8c82..cdf118d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t090501-c5525-flt-r-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
index 1447644..7df19aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-00-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
index a8ccf0e..42e898d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t100304-c43-rpl-bbx-01-d-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1004-c5524-width-00-b-g-expected.png b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1004-c5524-width-00-b-g-expected.png
index e50b00ed..6715bb1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css2.1/t1004-c5524-width-00-b-g-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css2.1/t1004-c5524-width-00-b-g-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/background/background-large-position-and-size-remains-stable-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/background/background-large-position-and-size-remains-stable-expected.png
index 2861135..f125d7aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/background/background-large-position-and-size-remains-stable-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/background/background-large-position-and-size-remains-stable-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
index 806e6b3..1a2fccd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/repeat/mask-negative-offset-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-expected.png
index c54a2d4..7c1edaf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-outset-expected.png
index 4840e2e..f4c816b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-outset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/block-mask-overlay-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-01-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-01-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-01-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-01-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-border-radius-expected.png
index 9f46c16..4b75a428 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-longhand-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-longhand-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-longhand-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-longhand-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-massive-scale-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-massive-scale-expected.png
index 8c751f6..df8f642 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-massive-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-massive-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-expected.png
index 2171979a..4f6d27d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png
index 2171979a..4f6d27d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-outset-in-shorthand-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-round-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-round-expected.png
index 19b673b..659541e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-round-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-repeat-round-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-rotate-transform-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-rotate-transform-expected.png
index 0d2ed27..d222c44 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-rotate-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-rotate-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scale-transform-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scale-transform-expected.png
index d59f93ec..1fbeaa2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scale-transform-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scale-transform-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scaled-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scaled-expected.png
index e7f9fc87..780121d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scaled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scaled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scrambled-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scrambled-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scrambled-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-scrambled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-side-reduction-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-side-reduction-expected.png
index 67937608..a58b50ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-side-reduction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-side-reduction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-slices-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-slices-expected.png
index cf38daa..5b4456b1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-slices-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-slices-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-source-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-expected.png
index be2082b..9d71311e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/inline-mask-overlay-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/scaled-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/scaled-border-image-expected.png
index 19e71444..b80f326e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/scaled-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/scaled-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 156b961..b507aef 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
index 573715a..e4017e6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
index ea9645d..450a897 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/hidpi/broken-image-with-size-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/hidpi/broken-image-with-size-hidpi-expected.png
index 7737110..765b175 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/hidpi/broken-image-with-size-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/hidpi/broken-image-with-size-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/001-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/001-expected.png
index c3cfbd27..2fa206b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/002-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/002-expected.png
index 07fc8bfb..9c11af5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/003-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/003-expected.png
index 07fc8bfb..9c11af5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/absolute-image-sizing-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/absolute-image-sizing-expected.png
index 4e4b95d..cb1cd8a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/absolute-image-sizing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/absolute-image-sizing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
index f5d2c82..3b3a4e7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-image-source-expected.png
index 455f42d..5f659861 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/imagemap-focus-ring-zero-outline-width-expected.png
index f7eaca7..1b230446 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-poster-scale-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-poster-scale-expected.png
index 0a10bdc0..3fb5e494 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/video-poster-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/video-poster-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
index 0566b8fa..a285e9a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/relative-sized-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index 5710651..303736bf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
index a2ca8e28..7439b8d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
index 8069c1db..55afff1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
index 0a9e678..52a7c53 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
index 8b9e8fc8..5721e6b92 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
index 70bf0eca..b0681e7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
index e9b33fc8..d476507 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
index 75b59dd..2d24913 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
index e9b33fc8..d476507 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
index 75b59dd..2d24913 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
index 75b59dd..2d24913 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
index e9b33fc8..d476507 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
index e9b33fc8..d476507 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
index 75b59dd..2d24913 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
index 75b59dd..2d24913 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
index e9b33fc8..d476507 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-no-markup-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-no-markup-expected.png
index 13bad595..c9cc11b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-no-markup-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-anchor-no-markup-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
index 8069c1db..55afff1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
index 1cc16816..663d0d16 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
index 8b9e8fc8..5721e6b92 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
index f6c4ae65..952fa4d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
index 56de668..caca8e8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
index 7c05aa43..1b175808 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
index 454223db..9c5eea8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
index 454223db..9c5eea8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
index df82b20..a22a455 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
index 270dba2f..1d51e92 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
index 270dba2f..1d51e92 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
index 64f74aa..ffe1b02 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
index 2176dfab..52880ddd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
index 2176dfab..52880ddd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
index dee086a..0d5c976 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
index dee086a..0d5c976 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
index 2b7685f..041724c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
index 2b7685f..041724c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
index b200beb..491b61e3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-ltr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-ltr-expected.png
index b81206f4..c116a9d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-ltr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-ltr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-rtl-expected.png
index 4ce33c1..b7c1e42 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-I18N/tspan-direction-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
index cf47b71..170203e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-blend-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
index f51e0ab..2cf660ad 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
index 293d46e..50cfc09 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/render-groups-03-t-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
index 5fae72b6..f93e22e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-image/image-preserveAspectRatio-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-image/image-preserveAspectRatio-all-expected.png
index 00e6cea..5aace34 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-image/image-preserveAspectRatio-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-image/image-preserveAspectRatio-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
index e51113d..e62e326 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/clip-mask-negative-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
index 648d7b5..d57f21b2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/perf/004-expected.png
Binary files differ
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/tables/mozilla/bugs/bug137388-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug137388-2-expected.png
index 2a8dea6..dc2c69d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug137388-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug137388-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug15544-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug15544-expected.png
index 3d7d71f..377f81b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug15544-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug15544-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug23235-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug23235-expected.png
index 0da1ab2..a0b8352 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug23235-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug23235-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug86708-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug86708-expected.png
index 869f522..dae652b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug86708-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/bugs/bug86708-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_baseline-expected.png
index 06465202..1a6d75a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_bottom-expected.png
index 3b04fe2..23128d67 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_middle-expected.png
index 1c1ffc3..ae1ecd6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_top-expected.png
index 40566d0..ad8355b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tbody_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_baseline-expected.png
index e2f1886..5447871 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_bottom-expected.png
index a20974a..5bee11f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_middle-expected.png
index c517b71..f376e0e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_top-expected.png
index a0dcd53..bb8e348 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/td_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
index 2a45094..2be9d27 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
index eb824ef..a6b5981 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_middle-expected.png
index c5c6d685..97a66af6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_top-expected.png
index 62f8a2b..eb8efb1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tfoot_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_baseline-expected.png
index 7188c4f..f83d9eb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_bottom-expected.png
index b5013d6..fe5e6fb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_middle-expected.png
index c157946..9eeef79 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_top-expected.png
index f3f7b2f..362a7938 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/th_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_baseline-expected.png
index 65615d04..0c9559c3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_bottom-expected.png
index ce24b3d..32992e9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_middle-expected.png
index b036ecfd..93232d9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_top-expected.png
index 35fe9e8..b6f08b3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/thead_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_baseline-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_baseline-expected.png
index 6101abf..ccd43d3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_baseline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_baseline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_bottom-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_bottom-expected.png
index a65520b..ab27f276 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_bottom-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_bottom-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_middle-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_middle-expected.png
index 3d04bd0..9c739cc4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_middle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_middle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_top-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_top-expected.png
index 5acb058..a9cf8ed7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_top-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla/marvin/tr_valign_top-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/97619-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/97619-expected.png
index 8ff064e..34b01c98 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/97619-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/97619-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug1647-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug1647-expected.png
index e4e0394..9b8c037 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug1647-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/bugs/bug1647-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 156b961..b507aef 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
index 159283a..cf6bd2a7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
index fd6e5085..e400cca8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
index 966eacb..56af6cb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-jpeg-maximum-quality-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
index 06cdb980..360103a1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-toDataURL-webp-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index a2ca8e28..7439b8d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
index a2ca8e28..7439b8d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
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/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
index ab66168..63ad4625 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
index ea30c4b..86eb9f75 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
index 1a4fb1e..0ac758e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
index b444838..4e2de0cd 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
index 1abe3a74..63777fb3 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
index 598aca8f..d99814f 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/g-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
index c42445e..6eebb26 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
index e1667951..32e7bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
index c42445e..6eebb26 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
index e1667951..32e7bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirNone-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
index e1667951..32e7bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
index c42445e..6eebb26 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
index c42445e..6eebb26 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
index e1667951..32e7bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
index e1667951..32e7bdb 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
index c42445e..6eebb26 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-no-markup-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-no-markup-expected.png
index 3920ea5b..b293e60 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-no-markup-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-anchor-no-markup-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
index 1a4fb1e..0ac758e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
index 7889bda..88b9139d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirLTR-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubNone-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
index 1abe3a74..63777fb3 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubNone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
index 6309e69..e2fdce19 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/text-dirRTL-ubOverride-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
index 2adc503..4a45742e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
index 27f871d..7e0c052 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
index 791cfc1d..434075f 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
index 791cfc1d..434075f 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
index fe25db2..30a9a7a 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
index fa03743..fcdf24e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
index fa03743..fcdf24e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
index 2620f55..3599a45 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
index d43f2f9d..35b4b46b 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
index d43f2f9d..35b4b46b 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
index 6dfba26..42391919 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
index 6dfba26..42391919 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
index d8569f35..f217993 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
index d8569f35..f217993 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
index 353a8eae..3b123ef2 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-ltr-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-ltr-expected.png
index c240ead6..a95917de 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-ltr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-ltr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-rtl-expected.png
index 837dd365..cd4ab5c 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-I18N/tspan-direction-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
index ea30c4b..86eb9f75 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
index ea30c4b..86eb9f75 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations-expected.png
Binary files differ
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/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-dom-mode-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
index fee118cd..3cc07b2 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEBlendElement-svgdom-mode-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/tables/mozilla/bugs/bug12910-2-expected.png b/third_party/WebKit/LayoutTests/tables/mozilla/bugs/bug12910-2-expected.png
index 9567c2567..9c2064af 100644
--- a/third_party/WebKit/LayoutTests/tables/mozilla/bugs/bug12910-2-expected.png
+++ b/third_party/WebKit/LayoutTests/tables/mozilla/bugs/bug12910-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/tables/mozilla_expected_failures/bugs/bug85016-expected.png b/third_party/WebKit/LayoutTests/tables/mozilla_expected_failures/bugs/bug85016-expected.png
index fd69cae..3ab9635e 100644
--- a/third_party/WebKit/LayoutTests/tables/mozilla_expected_failures/bugs/bug85016-expected.png
+++ b/third_party/WebKit/LayoutTests/tables/mozilla_expected_failures/bugs/bug85016-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html b/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html
index faf45ac..bb8c9cf 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html
@@ -1,8 +1,10 @@
 <!DOCTYPE html>
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
+<script src="resources/comparisons.js"></script>
 
 <script>
+let EPSILON = 1e-6;
 
 test(() => {
   let percentValue = new CSSUnitValue(10, 'percent');
@@ -41,5 +43,27 @@
   assert_false(perspective.is2D);
 }, "Setting is2D does nothing");
 
+test(() => {
+  // Obtained by doing $0.style.transform = perspective(10px);
+  // getComputedStyle($0).transform
+  let expectedMatrix = new DOMMatrixReadOnly(
+      [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.1, 0, 0, 0, 1]);
+  let transformValue = new CSSTransformValue([new CSSPerspective(CSS.px(10))]);
+  assert_matrix_approx_equals(
+      transformValue.toMatrix(), expectedMatrix, EPSILON);
+}, "toMatrix when used in a CSSTransformValue produces correct matrix");
+
+test(() => {
+  let expectedMatrix = new DOMMatrixReadOnly();
+  let transformValue = new CSSTransformValue([new CSSPerspective(CSS.em(10))]);
+  assert_matrix_approx_equals(transformValue.toMatrix(), expectedMatrix, EPSILON);
+}, "toMatrix is the identity (instead of crashing) if relative units are used");
+
+test(() => {
+  let expectedMatrix = new DOMMatrixReadOnly();
+  let transformValue = new CSSTransformValue([new CSSPerspective(CSS.px(-10))]);
+  assert_matrix_approx_equals(transformValue.toMatrix(), expectedMatrix, EPSILON);
+}, "toMatrix is the identity when perspective is negative (which is invalid)");
+
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/transform.html b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/transform.html
index 434eee75..fb59efc 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/transform.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/transform.html
@@ -52,7 +52,8 @@
     cssTransformWithRotate3D(1, 2, 3, angleValue(2, 'grad')),
     cssTransformWithRotate3D(1, 2, 3, angleValue(0.2, 'turn')),
     // Perspectives
-    // TODO(meade)
+    new CSSTransformValue([new CSSPerspective(CSS.px(10))]),
+    new CSSTransformValue([new CSSPerspective(CSS.em(5))]),
   ],
   // Values with these strings aren't used in Typed OM, but can also be
   // represented by the specified values.
@@ -106,60 +107,39 @@
   invalidObjects: [new CSSUnitValue(4, 'px')]
 });
 
+let crashTestStrings = {
+  'rotate(calc(45deg + 1rad))': 'rotate(calc(102.296deg))',
+  'rotate3d(1, 2, 3, calc(45deg + 1rad))': 'rotate3d(1, 2, 3, calc(102.296deg))',
+  'skew(calc(5deg + 0.1rad))': 'skew(calc(10.7296deg))',
+  'skew(calc(5deg + 0.1rad), 5deg)': 'skew(calc(10.7296deg), 5deg)',
+  'skew(5deg, calc(5deg + 0.1rad))': 'skew(5deg, calc(10.7296deg))',
+  'skewX(calc(5deg + 0.1rad))': 'skewX(calc(10.7296deg))',
+  'skewY(calc(5deg + 0.1rad))': 'skewY(calc(10.7296deg))',
+  'perspective(calc(10px + 5em))': 'perspective(calc(10px + 5em))',
+};
+
+for (let inputString in crashTestStrings) {
+  test(() => {
+    testElement.style.transform = inputString;
+    let result = testElement.styleMap.get('transform');
+    assert_equals(result.constructor, CSSStyleValue,
+        'result is a base CSSStyleValue');
+    assert_equals(result.toString(), crashTestStrings[inputString]);
+  }, "Getting transform when it is set to " + inputString + " does not crash");
+}
+
 // TODO(meade): Remove/update this test once translate is supported.
 test(function() {
   testElement.style.transform = 'translateY(50px)';
   testElement.styleMap.entries();
-}, "Unhandled case doesn't crash.");
+}, "Unhandled translate case doesn't crash.");
 
 test(function() {
-  testElement.style.transform = 'rotate(calc(45deg + 1rad))';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.constructor, CSSStyleValue,
-      'result is a base CSSStyleValue');
-  assert_equals(result.toString(), 'rotate(calc(102.296deg))');
-}, 'Getting transform when it has a rotate with a calc angle does not crash');
-
-test(function() {
-  testElement.style.transform = 'rotate3d(1, 2, 3, calc(45deg + 1rad))';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.constructor, CSSStyleValue,
-      'result is a base CSSStyleValue');
-  assert_equals(result.toString(), 'rotate3d(1, 2, 3, calc(102.296deg))');
-}, 'Getting transform when it has a rotate3d with a calc angle does not crash');
-
-test(function() {
-  testElement.style.transform = 'skew(calc(5deg + 0.1rad))';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.toString(), 'skew(calc(10.7296deg))');
-  assert_equals(result.constructor,  CSSStyleValue);
-}, 'Getting transform when it has a skew with a calc angle does not crash');
-
-test(function() {
-  testElement.style.transform = 'skew(calc(5deg + 0.1rad), 5deg)';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.toString(), 'skew(calc(10.7296deg), 5deg)');
-  assert_equals(result.constructor,  CSSStyleValue);
-
-  testElement.style.transform = 'skew(5deg, calc(5deg + 0.1rad))';
-  result = testElement.styleMap.get('transform');
-  assert_equals(result.toString(), 'skew(5deg, calc(10.7296deg))');
-  assert_equals(result.constructor,  CSSStyleValue);
-}, 'Getting transform when it has a 2-argument skew with a calc angle ' +
-   'does not crash');
-
-test(function() {
-  testElement.style.transform = 'skewX(calc(5deg + 0.1rad))';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.toString(), 'skewX(calc(10.7296deg))');
-  assert_equals(result.constructor,  CSSStyleValue);
-}, 'Getting transform when it has a skewX with a calc angle does not crash');
-
-test(function() {
-  testElement.style.transform = 'skewY(calc(5deg + 0.1rad))';
-  let result = testElement.styleMap.get('transform');
-  assert_equals(result.toString(), 'skewY(calc(10.7296deg))');
-  assert_equals(result.constructor,  CSSStyleValue);
-}, 'Getting transform when it has a skewY with a calc angle does not crash');
+  // Clear transform
+  let transform = new CSSTransformValue([new CSSPerspective(CSS.px(-5))]);
+  assert_throws(new TypeError(), () => {
+    testElement.styleMap.set('transform', transform);
+  });
+}, "Invalid perspective (negative length) doesn't crash");
 
 </script>
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/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
index 5c43446..aa260b3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
@@ -28,8 +28,11 @@
     ScriptState* script_state,
     CustomElementRegistry* registry,
     const v8::Local<v8::Value>& constructor) {
-  auto private_id =
-      script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
+  V8PerContextData* per_context_data = script_state->PerContextData();
+  // TODO(yukishiino): Remove this check when crbug.com/583429 is fixed.
+  if (UNLIKELY(!per_context_data))
+    return nullptr;
+  auto private_id = per_context_data->GetPrivateCustomElementDefinitionId();
   v8::Local<v8::Value> id_value;
   if (!constructor.As<v8::Object>()
            ->GetPrivate(script_state->GetContext(), private_id)
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/bindings/tests/idls/core/TestObject.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestObject.idl
index 19292ab..12d8b7b 100644
--- a/third_party/WebKit/Source/bindings/tests/idls/core/TestObject.idl
+++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestObject.idl
@@ -521,7 +521,7 @@
     // [OriginTrialEnabled=FeatureName3] void partiallyOriginTrialEnabledOverloadedVoidMethod(long longArg, DOMString stringArg, TestInterface testInterfaceArg);
     [PerWorldBindings] void perWorldBindingsVoidMethod();
     [PerWorldBindings] void perWorldBindingsVoidMethodTestInterfaceEmptyArg(TestInterfaceEmpty testInterfaceEmptyArg);
-    [PostMessage, RaisesException] void postMessage(SerializedScriptValue message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(SerializedScriptValue message, optional sequence<object> transfer);
     [LogActivity, LogAllWorlds, PerWorldBindings] void activityLoggingForAllWorldsPerWorldBindingsVoidMethod();
     [LogActivity, PerWorldBindings] void activityLoggingForIsolatedWorldsPerWorldBindingsVoidMethod();
     [RaisesException] void raisesExceptionVoidMethod();
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
index abca1805..69f722a 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -36,7 +36,6 @@
 #include "bindings/core/v8/V8HTMLElement.h"
 #include "bindings/core/v8/V8Int32Array.h"
 #include "bindings/core/v8/V8Iterator.h"
-#include "bindings/core/v8/V8MessagePort.h"
 #include "bindings/core/v8/V8Node.h"
 #include "bindings/core/v8/V8NodeFilterCondition.h"
 #include "bindings/core/v8/V8ShadowRoot.h"
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index f38ae4d..7af03c5 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -551,7 +551,7 @@
             'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants,
         }
 
-    @template_expander.use_jinja('ComputedStyleBase.h.tmpl', tests={'in': lambda a, b: a in b})
+    @template_expander.use_jinja('templates/ComputedStyleBase.h.tmpl', tests={'in': lambda a, b: a in b})
     def generate_base_computed_style_h(self):
         return {
             'properties': self._properties,
@@ -561,7 +561,7 @@
             'diff_functions_map': self._diff_functions_map,
         }
 
-    @template_expander.use_jinja('ComputedStyleBase.cpp.tmpl', tests={'in': lambda a, b: a in b})
+    @template_expander.use_jinja('templates/ComputedStyleBase.cpp.tmpl', tests={'in': lambda a, b: a in b})
     def generate_base_computed_style_cpp(self):
         return {
             'properties': self._properties,
@@ -571,7 +571,7 @@
             'diff_functions_map': self._diff_functions_map,
         }
 
-    @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl')
+    @template_expander.use_jinja('templates/ComputedStyleBaseConstants.h.tmpl')
     def generate_base_computed_style_constants(self):
         return {
             'properties': self._properties,
diff --git a/third_party/WebKit/Source/build/scripts/make_css_primitive_value_unit_trie.py b/third_party/WebKit/Source/build/scripts/make_css_primitive_value_unit_trie.py
index b59a8d2e..2b2081c 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_primitive_value_unit_trie.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_primitive_value_unit_trie.py
@@ -20,7 +20,7 @@
             'CSSPrimitiveValueUnitTrie.cpp': self.generate_implementation
         }
 
-    @template_expander.use_jinja('CSSPrimitiveValueUnitTrie.cpp.tmpl')
+    @template_expander.use_jinja('templates/CSSPrimitiveValueUnitTrie.cpp.tmpl')
     def generate_implementation(self):
         return {
             'length_tries': trie_builder.trie_list_by_str_length(self._units)
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
index 7dfc9462..0b822c4 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
@@ -103,7 +103,7 @@
             for property_enum in property_enums_for_class[api_class.classname]:
                 self._descriptor_indices[property_enum] = {'id': api_class.index, 'api': api_class.classname}
 
-    @template_expander.use_jinja('CSSPropertyDescriptor.cpp.tmpl')
+    @template_expander.use_jinja('templates/CSSPropertyDescriptor.cpp.tmpl')
     def generate_property_descriptor_cpp(self):
         return {
             'api_classes': self._api_classes,
@@ -112,7 +112,7 @@
             'invalid_descriptor_index': self._invalid_descriptor_index
         }
 
-    @template_expander.use_jinja('CSSPropertyDescriptor.h.tmpl')
+    @template_expander.use_jinja('templates/CSSPropertyDescriptor.h.tmpl')
     def generate_property_descriptor_h(self):
         return {
             'ordered_api_method_names': self.ordered_api_method_names,
@@ -121,7 +121,7 @@
 
     # Provides a function object given the classname of the property.
     def generate_property_api_h_builder(self, api_classname, property_name):
-        @template_expander.use_jinja('CSSPropertyAPIFiles.h.tmpl')
+        @template_expander.use_jinja('templates/CSSPropertyAPIFiles.h.tmpl')
         def generate_property_api_h():
             return {
                 'api_classname': api_classname,
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_metadata.py b/third_party/WebKit/Source/build/scripts/make_css_property_metadata.py
index 500c85a334..6c5dc176 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_property_metadata.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_property_metadata.py
@@ -26,7 +26,7 @@
             property_value['supports_percentage'] = (
                 'Percent' in property_value['typedom_types'])
 
-    @template_expander.use_jinja('CSSPropertyMetadata.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/CSSPropertyMetadata.cpp.tmpl', filters=filters)
     def generate_css_property_metadata_cpp(self):
         return {
             'properties_including_aliases': self._properties_including_aliases,
diff --git a/third_party/WebKit/Source/build/scripts/make_css_value_id_mappings.py b/third_party/WebKit/Source/build/scripts/make_css_value_id_mappings.py
index 648310e..3e0ed2f4 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_value_id_mappings.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_value_id_mappings.py
@@ -17,7 +17,7 @@
             'CSSValueIDMappingsGenerated.h': self.generate_css_value_mappings,
         }
 
-    @template_expander.use_jinja('CSSValueIDMappingsGenerated.h.tmpl')
+    @template_expander.use_jinja('templates/CSSValueIDMappingsGenerated.h.tmpl')
     def generate_css_value_mappings(self):
         mappings = {}
         include_paths = set()
diff --git a/third_party/WebKit/Source/build/scripts/make_cssom_types.py b/third_party/WebKit/Source/build/scripts/make_cssom_types.py
index 8b16831..3249a131 100755
--- a/third_party/WebKit/Source/build/scripts/make_cssom_types.py
+++ b/third_party/WebKit/Source/build/scripts/make_cssom_types.py
@@ -40,13 +40,13 @@
             'CSSOMKeywords.cpp': self.generate_keywords,
         }
 
-    @template_expander.use_jinja('CSSOMTypes.cpp.tmpl')
+    @template_expander.use_jinja('templates/CSSOMTypes.cpp.tmpl')
     def generate_types(self):
         return {
             'properties': self._properties,
         }
 
-    @template_expander.use_jinja('CSSOMKeywords.cpp.tmpl')
+    @template_expander.use_jinja('templates/CSSOMKeywords.cpp.tmpl')
     def generate_keywords(self):
         return {
             'properties': self._properties,
diff --git a/third_party/WebKit/Source/build/scripts/make_element_factory.py b/third_party/WebKit/Source/build/scripts/make_element_factory.py
index 68606172..33f1258 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_factory.py
@@ -83,11 +83,11 @@
             'fallback_js_interface': fallback_js_interface,
         })
 
-    @template_expander.use_jinja('ElementFactory.h.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/ElementFactory.h.tmpl', filters=filters)
     def generate_factory_header(self):
         return self._template_context
 
-    @template_expander.use_jinja('ElementFactory.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/ElementFactory.cpp.tmpl', filters=filters)
     def generate_factory_implementation(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py b/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
index 89b0d36b..9d80037 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_lookup_trie.py
@@ -64,13 +64,13 @@
             (self._namespace + 'ElementLookupTrie.cpp'): self.generate_implementation,
         }
 
-    @template_expander.use_jinja('ElementLookupTrie.h.tmpl')
+    @template_expander.use_jinja('templates/ElementLookupTrie.h.tmpl')
     def generate_header(self):
         return {
             'namespace': self._namespace,
         }
 
-    @template_expander.use_jinja('ElementLookupTrie.cpp.tmpl')
+    @template_expander.use_jinja('templates/ElementLookupTrie.cpp.tmpl')
     def generate_implementation(self):
         return {
             'namespace': self._namespace,
diff --git a/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py b/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
index 035bf730..7bd8fe2 100755
--- a/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
+++ b/third_party/WebKit/Source/build/scripts/make_element_type_helpers.py
@@ -71,11 +71,11 @@
         for tag in tags:
             tag['multipleTagNames'] = (interface_counts[tag['interface']] > 1 or tag['interface'] == self.fallback_interface)
 
-    @template_expander.use_jinja("ElementTypeHelpers.h.tmpl", filters=filters)
+    @template_expander.use_jinja("templates/ElementTypeHelpers.h.tmpl", filters=filters)
     def generate_helper_header(self):
         return self._template_context
 
-    @template_expander.use_jinja("ElementTypeHelpers.cpp.tmpl", filters=filters)
+    @template_expander.use_jinja("templates/ElementTypeHelpers.cpp.tmpl", filters=filters)
     def generate_helper_implementation(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py
index 3e4201b..e49ad9f 100755
--- a/third_party/WebKit/Source/build/scripts/make_event_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -170,7 +170,7 @@
             'includes': '\n'.join(self._headers_header_includes(self.json5_file.name_dictionaries)),
         }
 
-    @template_expander.use_jinja('EventFactory.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/EventFactory.cpp.tmpl', filters=filters)
     def generate_implementation(self):
         return {
             'namespace': self.namespace,
diff --git a/third_party/WebKit/Source/build/scripts/make_internal_runtime_flags.py b/third_party/WebKit/Source/build/scripts/make_internal_runtime_flags.py
index 88d9de8..c64da698 100755
--- a/third_party/WebKit/Source/build/scripts/make_internal_runtime_flags.py
+++ b/third_party/WebKit/Source/build/scripts/make_internal_runtime_flags.py
@@ -47,14 +47,14 @@
                          (self.class_name + '.h'): self.generate_header,
                         }
 
-    @template_expander.use_jinja(class_name + '.idl.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.idl.tmpl')
     def generate_idl(self):
         return {
             'features': self._features,
             'standard_features': self._standard_features,
         }
 
-    @template_expander.use_jinja(class_name + '.h.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.h.tmpl')
     def generate_header(self):
         return {
             'features': self._features,
diff --git a/third_party/WebKit/Source/build/scripts/make_internal_settings.py b/third_party/WebKit/Source/build/scripts/make_internal_settings.py
index 0838614..e6d5e7e 100755
--- a/third_party/WebKit/Source/build/scripts/make_internal_settings.py
+++ b/third_party/WebKit/Source/build/scripts/make_internal_settings.py
@@ -56,15 +56,15 @@
             'settings': self.json5_file.name_dictionaries,
         }
 
-    @template_expander.use_jinja('InternalSettingsGenerated.h.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/InternalSettingsGenerated.h.tmpl', filters=filters)
     def generate_header(self):
         return self._template_context
 
-    @template_expander.use_jinja('InternalSettingsGenerated.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/InternalSettingsGenerated.cpp.tmpl', filters=filters)
     def generate_implementation(self):
         return self._template_context
 
-    @template_expander.use_jinja('InternalSettingsGenerated.idl.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/InternalSettingsGenerated.idl.tmpl', filters=filters)
     def generate_idl(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_media_features.py b/third_party/WebKit/Source/build/scripts/make_media_features.py
index 22db174..397f3f2f 100755
--- a/third_party/WebKit/Source/build/scripts/make_media_features.py
+++ b/third_party/WebKit/Source/build/scripts/make_media_features.py
@@ -32,7 +32,7 @@
             'entries': self.json5_file.name_dictionaries,
         }
 
-    @template_expander.use_jinja('MediaFeatures.h.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/MediaFeatures.h.tmpl', filters=filters)
     def generate_header(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_names.py b/third_party/WebKit/Source/build/scripts/make_names.py
index a7473850..19488fb0 100755
--- a/third_party/WebKit/Source/build/scripts/make_names.py
+++ b/third_party/WebKit/Source/build/scripts/make_names.py
@@ -84,11 +84,11 @@
             'in_files': self.json5_file.file_paths,
         }
 
-    @template_expander.use_jinja("MakeNames.h.tmpl", filters=filters)
+    @template_expander.use_jinja("templates/MakeNames.h.tmpl", filters=filters)
     def generate_header(self):
         return self._template_context
 
-    @template_expander.use_jinja("MakeNames.cpp.tmpl", filters=filters)
+    @template_expander.use_jinja("templates/MakeNames.cpp.tmpl", filters=filters)
     def generate_implementation(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_origin_trials.py b/third_party/WebKit/Source/build/scripts/make_origin_trials.py
index e9fa2f7..609036d4 100755
--- a/third_party/WebKit/Source/build/scripts/make_origin_trials.py
+++ b/third_party/WebKit/Source/build/scripts/make_origin_trials.py
@@ -47,13 +47,13 @@
             (self.class_name + '.h'): self.generate_header,
         }
 
-    @template_expander.use_jinja(class_name + '.cpp.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.cpp.tmpl')
     def generate_implementation(self):
         return {
             'features': self._features,
         }
 
-    @template_expander.use_jinja(class_name + '.h.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.h.tmpl')
     def generate_header(self):
         return {
             'features': self._features,
diff --git a/third_party/WebKit/Source/build/scripts/make_qualified_names.py b/third_party/WebKit/Source/build/scripts/make_qualified_names.py
index fd263e5..c8bef43 100755
--- a/third_party/WebKit/Source/build/scripts/make_qualified_names.py
+++ b/third_party/WebKit/Source/build/scripts/make_qualified_names.py
@@ -95,11 +95,11 @@
             assert metadata == self.tags_json5_file.metadata[name].strip('"'), 'Both files must have the same %s.' % name
         return metadata
 
-    @template_expander.use_jinja('MakeQualifiedNames.h.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/MakeQualifiedNames.h.tmpl', filters=filters)
     def generate_header(self):
         return self._template_context
 
-    @template_expander.use_jinja('MakeQualifiedNames.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/MakeQualifiedNames.cpp.tmpl', filters=filters)
     def generate_implementation(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_runtime_features.py b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
index 9f647fb..1d7afe44 100755
--- a/third_party/WebKit/Source/build/scripts/make_runtime_features.py
+++ b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
@@ -71,11 +71,11 @@
             'standard_features': self._standard_features,
         }
 
-    @template_expander.use_jinja(class_name + '.h.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.h.tmpl')
     def generate_header(self):
         return self._template_inputs()
 
-    @template_expander.use_jinja(class_name + '.cpp.tmpl')
+    @template_expander.use_jinja('templates/' + class_name + '.cpp.tmpl')
     def generate_implementation(self):
         return self._template_inputs()
 
diff --git a/third_party/WebKit/Source/build/scripts/make_settings.py b/third_party/WebKit/Source/build/scripts/make_settings.py
index 431863a..c4f8e5e 100755
--- a/third_party/WebKit/Source/build/scripts/make_settings.py
+++ b/third_party/WebKit/Source/build/scripts/make_settings.py
@@ -75,7 +75,7 @@
             'settings': self.json5_file.name_dictionaries,
         }
 
-    @template_expander.use_jinja('SettingsMacros.h.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/SettingsMacros.h.tmpl', filters=filters)
     def generate_macros(self):
         return self._template_context
 
diff --git a/third_party/WebKit/Source/build/scripts/make_style_builder.py b/third_party/WebKit/Source/build/scripts/make_style_builder.py
index a8ca4c4..e0d4565 100755
--- a/third_party/WebKit/Source/build/scripts/make_style_builder.py
+++ b/third_party/WebKit/Source/build/scripts/make_style_builder.py
@@ -78,21 +78,21 @@
         for property in self._properties.values():
             apply_property_naming_defaults(property)
 
-    @template_expander.use_jinja('StyleBuilderFunctions.h.tmpl',
+    @template_expander.use_jinja('templates/StyleBuilderFunctions.h.tmpl',
                                  filters=filters)
     def generate_style_builder_functions_h(self):
         return {
             'properties': self._properties,
         }
 
-    @template_expander.use_jinja('StyleBuilderFunctions.cpp.tmpl',
+    @template_expander.use_jinja('templates/StyleBuilderFunctions.cpp.tmpl',
                                  filters=filters)
     def generate_style_builder_functions_cpp(self):
         return {
             'properties': self._properties,
         }
 
-    @template_expander.use_jinja('StyleBuilder.cpp.tmpl', filters=filters)
+    @template_expander.use_jinja('templates/StyleBuilder.cpp.tmpl', filters=filters)
     def generate_style_builder(self):
         return {
             'properties': self._properties,
diff --git a/third_party/WebKit/Source/build/scripts/make_style_shorthands.py b/third_party/WebKit/Source/build/scripts/make_style_shorthands.py
index 5110a30a..40f54cf6f 100755
--- a/third_party/WebKit/Source/build/scripts/make_style_shorthands.py
+++ b/third_party/WebKit/Source/build/scripts/make_style_shorthands.py
@@ -60,14 +60,14 @@
                 key=lambda property: (-len(property['longhand_property_ids']), property['name'])
             )
 
-    @template_expander.use_jinja('StylePropertyShorthand.cpp.tmpl')
+    @template_expander.use_jinja('templates/StylePropertyShorthand.cpp.tmpl')
     def generate_style_property_shorthand_cpp(self):
         return {
             'properties': self._properties,
             'longhands_dictionary': self._longhand_dictionary,
         }
 
-    @template_expander.use_jinja('StylePropertyShorthand.h.tmpl')
+    @template_expander.use_jinja('templates/StylePropertyShorthand.h.tmpl')
     def generate_style_property_shorthand_h(self):
         return {
             'properties': self._properties,
diff --git a/third_party/WebKit/Source/build/scripts/template_expander.py b/third_party/WebKit/Source/build/scripts/template_expander.py
index f23d3de1..2133195 100644
--- a/third_party/WebKit/Source/build/scripts/template_expander.py
+++ b/third_party/WebKit/Source/build/scripts/template_expander.py
@@ -36,11 +36,9 @@
 import jinja2
 
 
-def apply_template(path_to_template, params, filters=None, tests=None):
-    dirname, basename = os.path.split(path_to_template)
-    path_to_templates = os.path.join(_current_dir, 'templates')
+def apply_template(template_path, params, filters=None, tests=None):
     jinja_env = jinja2.Environment(
-        loader=jinja2.FileSystemLoader([dirname, path_to_templates]),
+        loader=jinja2.FileSystemLoader(_current_dir),
         keep_trailing_newline=True,  # newline-terminate generated files
         lstrip_blocks=True,  # so can indent control flow tags
         trim_blocks=True)  # so don't need {%- -%} everywhere
@@ -48,15 +46,15 @@
         jinja_env.filters.update(filters)
     if tests:
         jinja_env.tests.update(tests)
-    template = jinja_env.get_template(basename)
+    template = jinja_env.get_template(template_path)
     return template.render(params)
 
 
-def use_jinja(template_file_name, filters=None, tests=None):
+def use_jinja(template_path, filters=None, tests=None):
     def real_decorator(generator):
         def generator_internal(*args, **kwargs):
             parameters = generator(*args, **kwargs)
-            return apply_template(template_file_name, parameters, filters=filters, tests=tests)
+            return apply_template(template_path, parameters, filters=filters, tests=tests)
         generator_internal.func_name = generator.func_name
         return generator_internal
     return real_decorator
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPrimitiveValueUnitTrie.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPrimitiveValueUnitTrie.cpp.tmpl
index 61c62cd8..08cc090 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSPrimitiveValueUnitTrie.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSPrimitiveValueUnitTrie.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import trie_length_switch %}
+{% from 'templates/macros.tmpl' import trie_length_switch %}
 // 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.
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyDescriptor.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyDescriptor.cpp.tmpl
index 7903c3b..6b655dc 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyDescriptor.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyDescriptor.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license, print_if %}
+{% from 'templates/macros.tmpl' import license, print_if %}
 // 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.
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl
index ad04ff91..6693847d 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyMetadata.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #include "core/css/CSSPropertyMetadata.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
index 2f5e376..306224f9 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #ifndef CSSValueIDMappingsGenerated_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
index 41afe94..39dd1ae 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl
@@ -1,6 +1,6 @@
-{% from 'macros.tmpl' import license %}
-{% from 'fields/field.tmpl' import encode, getter_expression, setter_expression, fieldwise_copy, fieldwise_diff %}
-{% from 'fields/group.tmpl' import define_field_group_class %}
+{% from 'templates/macros.tmpl' import license, print_if %}
+{% from 'templates/fields/field.tmpl' import encode, getter_expression, setter_expression, fieldwise_copy, fieldwise_diff %}
+{% from 'templates/fields/group.tmpl' import define_field_group_class %}
 {{license()}}
 
 #include "core/ComputedStyleBase.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
index c5cf4494..6cd4335 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
@@ -1,6 +1,6 @@
-{% from 'macros.tmpl' import license %}
-{% from 'fields/field.tmpl' import encode, getter_expression, setter_expression, declare_storage, fieldwise_compare, fieldwise_copy, fieldwise_diff, fieldwise_pointer_compare_inherited %}
-{% from 'fields/group.tmpl' import declare_field_group_class %}
+{% from 'templates/macros.tmpl' import license, print_if %}
+{% from 'templates/fields/field.tmpl' import encode, getter_expression, setter_expression, declare_storage, fieldwise_compare, fieldwise_copy, fieldwise_diff, fieldwise_pointer_compare_inherited %}
+{% from 'templates/fields/group.tmpl' import declare_field_group_class %}
 {{license()}}
 
 #ifndef ComputedStyleBase_h
@@ -18,14 +18,14 @@
 {# Each field template has macros that we can call to generate specific
    aspects of the field (e.g. getters, setters).
 #}
-{% import 'fields/keyword.tmpl' as keyword %}
-{% import 'fields/multi_keyword.tmpl' as multi_keyword %}
-{% import 'fields/primitive.tmpl' as primitive %}
-{% import 'fields/monotonic_flag.tmpl' as monotonic_flag %}
-{% import 'fields/storage_only.tmpl' as storage_only %}
-{% import 'fields/external.tmpl' as external %}
-{% import 'fields/pointer.tmpl' as pointer %}
-{% from 'fields/field.tmpl' import encode %}
+{% import 'templates/fields/keyword.tmpl' as keyword %}
+{% import 'templates/fields/multi_keyword.tmpl' as multi_keyword %}
+{% import 'templates/fields/primitive.tmpl' as primitive %}
+{% import 'templates/fields/monotonic_flag.tmpl' as monotonic_flag %}
+{% import 'templates/fields/storage_only.tmpl' as storage_only %}
+{% import 'templates/fields/external.tmpl' as external %}
+{% import 'templates/fields/pointer.tmpl' as pointer %}
+{% from 'templates/fields/field.tmpl' import encode %}
 {% set field_templates = {
      'keyword': keyword,
      'multi_keyword': multi_keyword,
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBaseConstants.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBaseConstants.h.tmpl
index 03c41f8..ed3d5e2 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBaseConstants.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBaseConstants.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license, print_if %}
+{% from 'templates/macros.tmpl' import license, print_if %}
 {{license()}}
 
 #ifndef ComputedStyleBaseConstants_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementFactory.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementFactory.cpp.tmpl
index b7b4be5b..f2e7d81 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementFactory.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementFactory.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #include "{{namespace}}ElementFactory.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementFactory.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementFactory.h.tmpl
index b0379ba..91578240 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementFactory.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementFactory.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef {{namespace}}ElementFactory_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.cpp.tmpl
index 3bc573e..419231cc 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import trie_length_switch %}
+{% from 'templates/macros.tmpl' import trie_length_switch %}
 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.h.tmpl
index 34ec315..315d026 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementLookupTrie.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef {{namespace}}ElementLookupTrie_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
index 8ecbe99..be03580a 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #include "{{namespace}}ElementTypeHelpers.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.h.tmpl
index 4ea2e96..0ca5dcd3 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef {{namespace}}ElementTypeHelpers_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
index 1d5b5f8..260948b3 100644
--- a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 {% if suffix == 'Modules' %}
diff --git a/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.h.tmpl
index c84557c..2532d1a3 100644
--- a/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #ifndef InternalRuntimeFlags_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.idl.tmpl b/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.idl.tmpl
index 1ba1ed41..af9b7c4 100644
--- a/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.idl.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/InternalRuntimeFlags.idl.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 interface InternalRuntimeFlags {
diff --git a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.cpp.tmpl
index 66cdd9a0..2c5912a 100644
--- a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #include "InternalSettingsGenerated.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.h.tmpl
index a4c17b2..a0cf2bf 100644
--- a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef InternalSettingsGenerated_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.idl.tmpl b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.idl.tmpl
index e2cc6f67..d05f3ca 100644
--- a/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.idl.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/InternalSettingsGenerated.idl.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 interface InternalSettingsGenerated {
diff --git a/third_party/WebKit/Source/build/scripts/templates/MakeNames.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/MakeNames.cpp.tmpl
index 117281e..0b7249d 100644
--- a/third_party/WebKit/Source/build/scripts/templates/MakeNames.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/MakeNames.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #include "{{namespace}}{{suffix}}Names.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/MakeNames.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/MakeNames.h.tmpl
index 127eae9..45ef5e7bf 100644
--- a/third_party/WebKit/Source/build/scripts/templates/MakeNames.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/MakeNames.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef {{namespace}}{{suffix}}Names_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl
index 781fe0b..bc3f4b9 100644
--- a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #include "{{namespace}}Names.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.h.tmpl
index d9368d2..51e19b8 100644
--- a/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/MakeQualifiedNames.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef {{namespace}}Names_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/MediaFeatures.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/MediaFeatures.h.tmpl
index e357f3b..3bab025 100644
--- a/third_party/WebKit/Source/build/scripts/templates/MediaFeatures.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/MediaFeatures.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef MediaFeatures_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl
index 17c18c14..cd4f5a8b 100644
--- a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #include "core/origin_trials/OriginTrials.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl
index dc04fb3..89d7673b 100644
--- a/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/OriginTrials.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #ifndef OriginTrials_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
index 02a4016..4504e13 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #include "platform/RuntimeEnabledFeatures.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
index 62e848b..20dd74b 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #ifndef RuntimeEnabledFeatures_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl
index 51133c8..7dce98a 100644
--- a/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/SettingsMacros.h.tmpl
@@ -1,4 +1,4 @@
-{% from "macros.tmpl" import license %}
+{% from "templates/macros.tmpl" import license %}
 {{ license() }}
 
 #ifndef SettingsMacros_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/StyleBuilder.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/StyleBuilder.cpp.tmpl
index a47313fb..20566f5 100644
--- a/third_party/WebKit/Source/build/scripts/templates/StyleBuilder.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/StyleBuilder.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #include "core/css/resolver/StyleBuilder.h"
diff --git a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
index c6ea7fd3..a1696ed 100644
--- a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.cpp.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {#
     This file is for property handlers which use the templating engine to
     reduce (handwritten) code duplication.
diff --git a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.h.tmpl
index 76b8a00..aac62586 100644
--- a/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/StyleBuilderFunctions.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'templates/macros.tmpl' import license %}
 {{license()}}
 
 #ifndef StyleBuilderFunctions_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/base.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/base.tmpl
index 22448d8..7c938765 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/base.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/base.tmpl
@@ -1,4 +1,4 @@
-{% from 'fields/field.tmpl' import encode, decode, const_ref, nonconst_ref, getter_expression, setter_expression, set_if_changed %}
+{% from 'templates/fields/field.tmpl' import encode, decode, const_ref, nonconst_ref, getter_expression, setter_expression, set_if_changed %}
 
 {% macro decl_initial_method(field) -%}
 inline static {{field.type_name}} {{field.initial_method_name}}() {
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/external.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/external.tmpl
index 15c218b..f9793cc 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/external.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/external.tmpl
@@ -1,5 +1,5 @@
-{% import 'fields/base.tmpl' as base %}
-{% from 'fields/field.tmpl' import getter_expression, setter_expression %}
+{% import 'templates/fields/base.tmpl' as base %}
+{% from 'templates/fields/field.tmpl' import getter_expression, setter_expression %}
 
 {% macro decl_public_methods(field) %}
 {{base.decl_initial_method(field)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
index 6c1b5e1..ccc0986 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/field.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import print_if %}
+{% from 'templates/macros.tmpl' import print_if %}
 
 {% macro encode(field, value) %}
 {% if field.is_bit_field -%}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
index 1b2ff282..5a06dfdf 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/group.tmpl
@@ -1,5 +1,5 @@
-{% from 'fields/field.tmpl' import encode, declare_storage, compare %}
-{% from 'macros.tmpl' import print_if %}
+{% from 'templates/fields/field.tmpl' import encode, declare_storage, compare %}
+{% from 'templates/macros.tmpl' import print_if %}
 {% macro declare_field_group_class(group): -%}
 {% for subgroup in group.subgroups %}
 {{declare_field_group_class(subgroup)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/keyword.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/keyword.tmpl
index 69259e97..a426f35 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/keyword.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/keyword.tmpl
@@ -1,4 +1,4 @@
-{% import 'fields/base.tmpl' as base %}
+{% import 'templates/fields/base.tmpl' as base %}
 
 {% macro decl_public_methods(field) -%}
 {{base.decl_initial_method(field)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/monotonic_flag.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/monotonic_flag.tmpl
index 02b5cb5..d02d296 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/monotonic_flag.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/monotonic_flag.tmpl
@@ -1,6 +1,6 @@
-{% import 'fields/base.tmpl' as base %}
-{% from 'fields/field.tmpl' import encode, set_if_changed %}
-{% from 'macros.tmpl' import print_if %}
+{% import 'templates/fields/base.tmpl' as base %}
+{% from 'templates/fields/field.tmpl' import encode, set_if_changed %}
+{% from 'templates/macros.tmpl' import print_if %}
 
 {% macro decl_public_methods(field) %}
 {{base.decl_getter_method(field)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/multi_keyword.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/multi_keyword.tmpl
index 1b97b4f..8d672b81 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/multi_keyword.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/multi_keyword.tmpl
@@ -1,4 +1,4 @@
-{% import 'fields/keyword.tmpl' as keyword %}
+{% import 'templates/fields/keyword.tmpl' as keyword %}
 
 {% macro decl_public_methods(field) -%}
 {{keyword.decl_public_methods(field)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl
index 26837be0..ca32492f 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/pointer.tmpl
@@ -1,5 +1,5 @@
-{% import 'fields/base.tmpl' as base %}
-{% from 'fields/field.tmpl' import getter_expression, setter_expression, decode %}
+{% import 'templates/fields/base.tmpl' as base %}
+{% from 'templates/fields/field.tmpl' import getter_expression, setter_expression, decode %}
 
 {% macro decl_public_methods(field) %}
 static {{field.type_name}}* {{field.initial_method_name}}() {
@@ -17,4 +17,4 @@
 {% endif %}
 }
 
-{%- endmacro %}
\ No newline at end of file
+{%- endmacro %}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/primitive.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/primitive.tmpl
index 3e5e83f..fd001ee 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/primitive.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/primitive.tmpl
@@ -1,4 +1,4 @@
-{% import 'fields/base.tmpl' as base %}
+{% import 'templates/fields/base.tmpl' as base %}
 
 {% macro decl_public_methods(field) -%}
 {{base.decl_initial_method(field)}}
diff --git a/third_party/WebKit/Source/build/scripts/templates/fields/storage_only.tmpl b/third_party/WebKit/Source/build/scripts/templates/fields/storage_only.tmpl
index 6ce6baf9..3420c27 100644
--- a/third_party/WebKit/Source/build/scripts/templates/fields/storage_only.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/fields/storage_only.tmpl
@@ -1,5 +1,5 @@
-{% import 'fields/base.tmpl' as base %}
-{% from 'fields/field.tmpl' import getter_expression, setter_expression %}
+{% import 'templates/fields/base.tmpl' as base %}
+{% from 'templates/fields/field.tmpl' import getter_expression, setter_expression %}
 
 {% macro decl_public_methods(field) -%}
 {{base.decl_initial_method(field)}}
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 2e8e035b..7bb7cd3 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -599,6 +599,7 @@
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPITextDecoration.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIWebkitMarginCollapse.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.h",
   ]
 }
 
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/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 8094d8d4..4406da3 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -527,6 +527,8 @@
     "properties/CSSPropertyPositionUtils.h",
     "properties/CSSPropertyShapeUtils.cpp",
     "properties/CSSPropertyShapeUtils.h",
+    "properties/CSSPropertyTextDecorationLineUtils.cpp",
+    "properties/CSSPropertyTextDecorationLineUtils.h",
     "properties/CSSPropertyTransformUtils.cpp",
     "properties/CSSPropertyTransformUtils.h",
     "properties/CSSPropertyTransitionPropertyUtils.cpp",
@@ -546,6 +548,7 @@
     "properties/CSSShorthandPropertyAPITextDecoration.cpp",
     "properties/CSSShorthandPropertyAPIWebkitMarginCollapse.cpp",
     "properties/CSSShorthandPropertyAPIWebkitMaskBoxImage.cpp",
+    "properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp",
     "resolver/AnimatedStyleBuilder.cpp",
     "resolver/AnimatedStyleBuilder.h",
     "resolver/CSSPropertyPriority.h",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 596d845c..2f9e9dbc 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -1467,7 +1467,7 @@
       name: "image-rendering",
       inherited: true,
       field_template: "keyword",
-      keywords: ["auto", "optimize-speed", "optimize-quality", "-webkit-optimize-contrast", "pixelated"],
+      keywords: ["auto", "optimizeSpeed", "optimizeQuality", "-webkit-optimize-contrast", "pixelated"],
       default_value: "auto",
       field_group: "rare-inherited",
     },
@@ -2092,7 +2092,7 @@
       type_name: "ScrollBehavior",
       field_template: "storage_only",
       field_group: "rare-non-inherited",
-      field_size: 2,
+      field_size: 2, // FIXME: Convert this to a keyword field
       default_value: "kScrollBehaviorAuto",
       default_generated_functions: ["getter", "setter"],
     },
@@ -2476,7 +2476,7 @@
       field_template: "keyword",
       getter: "GetTextAlign",
       keywords: [
-        "left", "right", "center", "justify", "webkitLeft", "webkitRight", "webkitCenter", "start", "end",
+        "left", "right", "center", "justify", "-webkit-left", "-webkit-right", "-webkit-center", "start", "end",
       ],
     },
     {
@@ -2523,6 +2523,8 @@
     {
       name: "text-decoration-line",
       api_class: "CSSPropertyAPITextDecorationLine",
+      api_methods: ["parseSingleValue"],
+      api_class: "CSSPropertyAPITextDecorationLine",
       converter: "ConvertFlags<TextDecoration>",
       name_for_methods: "TextDecoration",
       runtime_flag: "CSS3TextDecorations",
@@ -3594,6 +3596,8 @@
     {
       name: "-webkit-text-decorations-in-effect",
       api_class: "CSSPropertyAPITextDecorationLine",
+      api_methods: ["parseSingleValue"],
+      api_class: "CSSPropertyAPITextDecorationLine",
       builder_skip: true,
       inherited: true,
     },
@@ -3920,6 +3924,8 @@
     {
       name: "-webkit-text-emphasis",
       longhands: ["-webkit-text-emphasis-style", "-webkit-text-emphasis-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "-webkit-text-stroke",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 2ef704d..1c111c4 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -409,7 +409,7 @@
       field_template: "storage_only",
       type_name: "TextEmphasisMark",
       default_value: "TextEmphasisMark::kNone",
-      field_size: 3,
+      keywords: ["none", "auto", "dot", "circle", "double-circle", "triangle", "sesame", "custom"],
       field_group: "rare-inherited",
     },
     {
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSPerspective.cpp b/third_party/WebKit/Source/core/css/cssom/CSSPerspective.cpp
index d32ad93..aa9df3b 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSPerspective.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSPerspective.cpp
@@ -5,6 +5,8 @@
 #include "core/css/cssom/CSSPerspective.h"
 
 #include "bindings/core/v8/ExceptionState.h"
+#include "core/css/cssom/CSSUnitValue.h"
+#include "core/geometry/DOMMatrix.h"
 
 namespace blink {
 
@@ -49,7 +51,30 @@
   return new CSSPerspective(length);
 }
 
+DOMMatrix* CSSPerspective::AsMatrix() const {
+  if (!length_->IsCalculated() && ToCSSUnitValue(length_)->value() < 0) {
+    // Negative values are invalid.
+    // https://github.com/w3c/css-houdini-drafts/issues/420
+    return nullptr;
+  }
+  CSSUnitValue* length = length_->to(CSSPrimitiveValue::UnitType::kPixels);
+  if (!length) {
+    // This can happen if there are relative units. TODO(meade): How to resolve
+    // relative units here?
+    // https://github.com/w3c/css-houdini-drafts/issues/421
+    return nullptr;
+  }
+  DOMMatrix* matrix = DOMMatrix::Create();
+  matrix->perspectiveSelf(length->value());
+  return matrix;
+}
+
 CSSFunctionValue* CSSPerspective::ToCSSValue() const {
+  if (!length_->IsCalculated() && ToCSSUnitValue(length_)->value() < 0) {
+    // Negative values are invalid.
+    // https://github.com/w3c/css-houdini-drafts/issues/420
+    return nullptr;
+  }
   CSSFunctionValue* result = CSSFunctionValue::Create(CSSValuePerspective);
   result->Append(*length_->ToCSSValue());
   return result;
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSPerspective.h b/third_party/WebKit/Source/core/css/cssom/CSSPerspective.h
index f27abc30..c344fda8 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSPerspective.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSPerspective.h
@@ -39,8 +39,7 @@
 
   // Internal methods - from CSSTransformComponent.
   TransformComponentType GetType() const final { return kPerspectiveType; }
-  // TODO: Implement AsMatrix for CSSPerspective.
-  DOMMatrix* AsMatrix() const final { return nullptr; }
+  DOMMatrix* AsMatrix() const final;
   CSSFunctionValue* ToCSSValue() const final;
 
   DEFINE_INLINE_VIRTUAL_TRACE() {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index df0e842..d65ea97 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -45,6 +45,7 @@
 #include "core/css/properties/CSSPropertyMarginUtils.h"
 #include "core/css/properties/CSSPropertyOffsetRotateUtils.h"
 #include "core/css/properties/CSSPropertyPositionUtils.h"
+#include "core/css/properties/CSSPropertyTextDecorationLineUtils.h"
 #include "core/css/properties/CSSPropertyTransitionPropertyUtils.h"
 #include "core/css/properties/CSSPropertyWebkitBorderWidthUtils.h"
 #include "core/frame/UseCounter.h"
@@ -568,28 +569,6 @@
   return list;
 }
 
-static CSSValue* ConsumeTextDecorationLine(CSSParserTokenRange& range) {
-  CSSValueID id = range.Peek().Id();
-  if (id == CSSValueNone)
-    return ConsumeIdent(range);
-
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  while (true) {
-    CSSIdentifierValue* ident =
-        ConsumeIdent<CSSValueBlink, CSSValueUnderline, CSSValueOverline,
-                     CSSValueLineThrough>(range);
-    if (!ident)
-      break;
-    if (list->HasValue(*ident))
-      return nullptr;
-    list->Append(*ident);
-  }
-
-  if (!list->length())
-    return nullptr;
-  return list;
-}
-
 static CSSValue* ConsumePerspective(CSSParserTokenRange& range,
                                     const CSSParserContext* context,
                                     bool use_legacy_parsing) {
@@ -1269,10 +1248,8 @@
       return ConsumeFilter(range_, context_);
     case CSSPropertyTextDecoration:
       DCHECK(!RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
-    // fallthrough
-    case CSSPropertyWebkitTextDecorationsInEffect:
-    case CSSPropertyTextDecorationLine:
-      return ConsumeTextDecorationLine(range_);
+      return CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(
+          range_);
     case CSSPropertyOffsetDistance:
       return ConsumeLengthOrPercent(range_, context_->Mode(), kValueRangeAll);
     case CSSPropertyOffsetRotate:
@@ -2379,8 +2356,6 @@
       return ConsumeShorthandGreedily(textDecorationShorthand(), important);
     case CSSPropertyPadding:
       return Consume4Values(paddingShorthand(), important);
-    case CSSPropertyWebkitTextEmphasis:
-      return ConsumeShorthandGreedily(webkitTextEmphasisShorthand(), important);
     case CSSPropertyOutline:
       return ConsumeShorthandGreedily(outlineShorthand(), important);
     case CSSPropertyWebkitBorderStart:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
index 00fc88d..52702f1 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
@@ -11,6 +11,7 @@
 #include "core/css/CSSGradientValue.h"
 #include "core/css/CSSImageSetValue.h"
 #include "core/css/CSSImageValue.h"
+#include "core/css/CSSInitialValue.h"
 #include "core/css/CSSPaintValue.h"
 #include "core/css/CSSStringValue.h"
 #include "core/css/CSSURIValue.h"
@@ -1633,6 +1634,49 @@
   return range.AtEnd();
 }
 
+bool ConsumeShorthandGreedilyViaLonghandAPIs(
+    const StylePropertyShorthand& shorthand,
+    bool important,
+    const CSSParserContext& context,
+    CSSParserTokenRange& range,
+    HeapVector<CSSProperty, 256>& properties) {
+  // Existing shorthands have at most 6 longhands.
+  DCHECK_LE(shorthand.length(), 6u);
+  const CSSValue* longhands[6] = {nullptr, nullptr, nullptr,
+                                  nullptr, nullptr, nullptr};
+  bool needs_legacy_parsing = false;
+
+  const CSSPropertyID* shorthand_properties = shorthand.properties();
+  do {
+    bool found_longhand = false;
+    for (size_t i = 0; !found_longhand && i < shorthand.length(); ++i) {
+      if (longhands[i])
+        continue;
+      longhands[i] =
+          ParseLonghandViaAPI(shorthand_properties[i], shorthand.id(), context,
+                              range, needs_legacy_parsing);
+      DCHECK(!needs_legacy_parsing);
+
+      if (longhands[i])
+        found_longhand = true;
+    }
+    if (!found_longhand)
+      return false;
+  } while (!range.AtEnd());
+
+  for (size_t i = 0; i < shorthand.length(); ++i) {
+    if (longhands[i]) {
+      AddProperty(shorthand_properties[i], shorthand.id(), *longhands[i],
+                  important, IsImplicitProperty::kNotImplicit, properties);
+    } else {
+      AddProperty(shorthand_properties[i], shorthand.id(),
+                  *CSSInitialValue::Create(), important,
+                  IsImplicitProperty::kNotImplicit, properties);
+    }
+  }
+  return true;
+}
+
 }  // namespace CSSPropertyParserHelpers
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
index a2b6a6a..a1850cb 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
@@ -131,12 +131,39 @@
                                     CSSParserTokenRange&,
                                     bool& needs_legacy_parsing);
 
+// ConsumeShorthandVia4LonghandsAPI and ConsumeShorthandGreedilyViaLonghandAPIs
+// are based on CSSPropertyParsers' Consume4Values and ConsumeShorthandGreedily.
+// They both delegate parsing of a shorthand property to its respective longhand
+// components. The difference is the functions in this Helpers file expect
+// component longhands to have API implementations already.
+// Consume4Values and ConsumeShorthandGreedily will be deprecated soon, when
+// shorthand properties are ribbonised (i.e. have their own APIs). Until then,
+// there is a slight code duplication between the two versions for the following
+// reasons:
+// 1. An alternative to code duplicate is to have the old Consume*
+//    (e.g. ConsumeShorthandGreedily) call the new Consume*
+//    (e.g. ConsumeShorthandGreedilyViaLonghandAPIs). However, the
+//    new Consume* expects ALL component longhands to have APIs and will parse
+///   all longhands via their APIs. In order to parse shorthands, where some
+//    component longhands do not have APIs, the new Consume* will need to return
+//    to the old Consume* which longhands have no APIs and thus are not parsed.
+//    The old Consume* will then have to parse these longhands separately.
+//    Hence there's added code complexity with little code reduction.
+// 2. All shorthand properties will have APIs soon, hence such code duplication
+//    is temporary only.
 bool ConsumeShorthandVia4LonghandsAPI(const StylePropertyShorthand&,
                                       bool important,
                                       const CSSParserContext&,
                                       CSSParserTokenRange&,
                                       HeapVector<CSSProperty, 256>& properties);
 
+bool ConsumeShorthandGreedilyViaLonghandAPIs(
+    const StylePropertyShorthand&,
+    bool important,
+    const CSSParserContext&,
+    CSSParserTokenRange&,
+    HeapVector<CSSProperty, 256>& properties);
+
 // Template implementations are at the bottom of the file for readability.
 
 template <typename... emptyBaseCase>
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationLine.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationLine.cpp
index e0c257e1..35dc68fd 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationLine.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationLine.cpp
@@ -4,4 +4,15 @@
 
 #include "core/css/properties/CSSPropertyAPITextDecorationLine.h"
 
-namespace blink {}  // namespace blink
+#include "core/css/properties/CSSPropertyTextDecorationLineUtils.h"
+
+namespace blink {
+
+const CSSValue* CSSPropertyAPITextDecorationLine::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext&,
+    const CSSParserLocalContext&) {
+  return CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(range);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.cpp
new file mode 100644
index 0000000..0771cb2c
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.cpp
@@ -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 "core/css/properties/CSSPropertyTextDecorationLineUtils.h"
+
+#include "core/CSSValueKeywords.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSParserTokenRange.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+class CSSIdentifierValue;
+
+CSSValue* CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(
+    CSSParserTokenRange& range) {
+  CSSValueID id = range.Peek().Id();
+  if (id == CSSValueNone)
+    return CSSPropertyParserHelpers::ConsumeIdent(range);
+
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  while (true) {
+    CSSIdentifierValue* ident =
+        CSSPropertyParserHelpers::ConsumeIdent<CSSValueBlink, CSSValueUnderline,
+                                               CSSValueOverline,
+                                               CSSValueLineThrough>(range);
+    if (!ident)
+      break;
+    if (list->HasValue(*ident))
+      return nullptr;
+    list->Append(*ident);
+  }
+
+  if (!list->length())
+    return nullptr;
+  return list;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.h b/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.h
new file mode 100644
index 0000000..0858110
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyTextDecorationLineUtils.h
@@ -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.
+
+#ifndef CSSPropertyTextDecorationLineUtils_h
+#define CSSPropertyTextDecorationLineUtils_h
+
+#include "platform/wtf/Allocator.h"
+
+namespace blink {
+
+class CSSParserTokenRange;
+class CSSValue;
+
+class CSSPropertyTextDecorationLineUtils {
+  STATIC_ONLY(CSSPropertyTextDecorationLineUtils);
+
+ public:
+  static CSSValue* ConsumeTextDecorationLine(CSSParserTokenRange&);
+};
+
+}  // namespace blink
+
+#endif  // CSSPropertyTextDecorationLineUtils_h
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp
new file mode 100644
index 0000000..3d299a1
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIWebkitTextEmphasis.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIWebkitTextEmphasis::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext& local_context,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      webkitTextEmphasisShorthand(), important, context, range, properties);
+}
+}  // namespace blink
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/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 8f532c3a..ef43282 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -82,12 +82,15 @@
   DOMTreeMutationDetector(const Node& node, const Node& parent)
       : node_document_(node.GetDocument()),
         parent_document_(parent.GetDocument()),
+        parent_(parent),
         original_node_document_version_(node_document_->DomTreeVersion()),
         original_parent_document_version_(parent_document_->DomTreeVersion()) {}
 
   bool HadAtMostOneDOMMutation() {
     if (node_document_->DomTreeVersion() > original_node_document_version_ + 1)
       return false;
+    if (parent_document_ != parent_->GetDocument())
+      return false;
     if (node_document_ == parent_document_)
       return true;
     return parent_document_->DomTreeVersion() ==
@@ -97,6 +100,7 @@
  private:
   const Member<Document> node_document_;
   const Member<Document> parent_document_;
+  const Member<const Node> parent_;
   const uint64_t original_node_document_version_;
   const uint64_t original_parent_document_version_;
 };
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/MessagePort.idl b/third_party/WebKit/Source/core/dom/MessagePort.idl
index f6eb2f8..d42739e4 100644
--- a/third_party/WebKit/Source/core/dom/MessagePort.idl
+++ b/third_party/WebKit/Source/core/dom/MessagePort.idl
@@ -32,7 +32,7 @@
     DependentLifetime,
     Exposed=(Window,Worker)
 ] interface MessagePort : EventTarget {
-    [PostMessage, RaisesException, Measure] void postMessage(any message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException, Measure] void postMessage(any message, optional sequence<object> transfer = []);
     [Measure] void start();
     [Measure] void close();
 
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 1ef87604..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/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 8b87be9..e79a3b3 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -436,23 +436,23 @@
 
   TextGranularity granularity;
   if (DeprecatedEqualIgnoringCase(granularity_string, "character"))
-    granularity = kCharacterGranularity;
+    granularity = TextGranularity::kCharacter;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "word"))
-    granularity = kWordGranularity;
+    granularity = TextGranularity::kWord;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "sentence"))
-    granularity = kSentenceGranularity;
+    granularity = TextGranularity::kSentence;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "line"))
-    granularity = kLineGranularity;
+    granularity = TextGranularity::kLine;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "paragraph"))
-    granularity = kParagraphGranularity;
+    granularity = TextGranularity::kParagraph;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "lineboundary"))
-    granularity = kLineBoundary;
+    granularity = TextGranularity::kLineBoundary;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "sentenceboundary"))
-    granularity = kSentenceBoundary;
+    granularity = TextGranularity::kSentenceBoundary;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "paragraphboundary"))
-    granularity = kParagraphBoundary;
+    granularity = TextGranularity::kParagraphBoundary;
   else if (DeprecatedEqualIgnoringCase(granularity_string, "documentboundary"))
-    granularity = kDocumentBoundary;
+    granularity = TextGranularity::kDocumentBoundary;
   else
     return;
 
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index 83d681d..0f51ead 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -2165,19 +2165,19 @@
   using InputType = InputEvent::InputType;
   switch (direction) {
     case DeleteDirection::kForward:
-      if (granularity == kWordGranularity)
+      if (granularity == TextGranularity::kWord)
         return InputType::kDeleteWordForward;
-      if (granularity == kLineBoundary)
+      if (granularity == TextGranularity::kLineBoundary)
         return InputType::kDeleteSoftLineForward;
-      if (granularity == kParagraphBoundary)
+      if (granularity == TextGranularity::kParagraphBoundary)
         return InputType::kDeleteHardLineForward;
       return InputType::kDeleteContentForward;
     case DeleteDirection::kBackward:
-      if (granularity == kWordGranularity)
+      if (granularity == TextGranularity::kWord)
         return InputType::kDeleteWordBackward;
-      if (granularity == kLineBoundary)
+      if (granularity == TextGranularity::kLineBoundary)
         return InputType::kDeleteSoftLineBackward;
-      if (granularity == kParagraphBoundary)
+      if (granularity == TextGranularity::kParagraphBoundary)
         return InputType::kDeleteHardLineBackward;
       return InputType::kDeleteContentBackward;
     default:
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index a733b51..764848a 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -377,7 +377,7 @@
 
 bool Editor::CanSmartCopyOrDelete() const {
   return SmartInsertDeleteEnabled() &&
-         GetFrame().Selection().Granularity() == kWordGranularity;
+         GetFrame().Selection().Granularity() == TextGranularity::kWord;
 }
 
 bool Editor::IsSelectTrailingWhitespaceEnabled() const {
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index be6bbd77..6c246c20 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -96,7 +96,7 @@
     : frame_(frame),
       layout_selection_(LayoutSelection::Create(*this)),
       selection_editor_(SelectionEditor::Create(frame)),
-      granularity_(kCharacterGranularity),
+      granularity_(TextGranularity::kCharacter),
       x_pos_for_vertical_arrow_navigation_(NoXPosForVerticalArrowNavigation()),
       focused_(frame.GetPage() &&
                frame.GetPage()->GetFocusController().FocusedFrame() == frame),
@@ -385,12 +385,13 @@
       kCloseTyping | kClearTypingStyle | user_triggered;
   SetSelection(selection_modifier.Selection().AsSelection(), options);
 
-  if (granularity == kLineGranularity || granularity == kParagraphGranularity)
+  if (granularity == TextGranularity::kLine ||
+      granularity == TextGranularity::kParagraph)
     x_pos_for_vertical_arrow_navigation_ =
         selection_modifier.XPosForVerticalArrowNavigation();
 
   if (user_triggered == kUserTriggered)
-    granularity_ = kCharacterGranularity;
+    granularity_ = TextGranularity::kCharacter;
 
   ScheduleVisualUpdateForPaintInvalidationIfNeeded();
 
@@ -412,13 +413,13 @@
                alter == kAlterationMove ? CursorAlignOnScroll::kAlways
                                         : CursorAlignOnScroll::kIfNeeded);
 
-  granularity_ = kCharacterGranularity;
+  granularity_ = TextGranularity::kCharacter;
 
   return true;
 }
 
 void FrameSelection::Clear() {
-  granularity_ = kCharacterGranularity;
+  granularity_ = TextGranularity::kCharacter;
   if (granularity_strategy_)
     granularity_strategy_->Clear();
   SetSelection(SelectionInDOMTree());
@@ -496,7 +497,7 @@
 }
 
 void FrameSelection::ContextDestroyed(Document* document) {
-  granularity_ = kCharacterGranularity;
+  granularity_ = TextGranularity::kCharacter;
 
   layout_selection_->OnDocumentShutdown();
 
@@ -1075,7 +1076,7 @@
                        .Extend(end.DeepEquivalent())
                        .Build(),
                    kCloseTyping | kClearTypingStyle,
-                   CursorAlignOnScroll::kIfNeeded, kWordGranularity);
+                   CursorAlignOnScroll::kIfNeeded, TextGranularity::kWord);
       return true;
     }
   }
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h
index 2dcf720..a5387f79 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.h
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -113,12 +113,12 @@
   void SetSelection(const SelectionInDOMTree&,
                     SetSelectionOptions = kCloseTyping | kClearTypingStyle,
                     CursorAlignOnScroll = CursorAlignOnScroll::kIfNeeded,
-                    TextGranularity = kCharacterGranularity);
+                    TextGranularity = TextGranularity::kCharacter);
 
   void SetSelection(const SelectionInFlatTree&,
                     SetSelectionOptions = kCloseTyping | kClearTypingStyle,
                     CursorAlignOnScroll = CursorAlignOnScroll::kIfNeeded,
-                    TextGranularity = kCharacterGranularity);
+                    TextGranularity = TextGranularity::kCharacter);
   void SelectAll(EUserTriggered = kNotUserTriggered);
   void Clear();
   bool IsHidden() const;
@@ -131,7 +131,7 @@
   bool SetSelectionDeprecated(const SelectionInDOMTree&,
                               SetSelectionOptions = kCloseTyping |
                                                     kClearTypingStyle,
-                              TextGranularity = kCharacterGranularity);
+                              TextGranularity = TextGranularity::kCharacter);
   void DidSetSelectionDeprecated(
       SetSelectionOptions = kCloseTyping | kClearTypingStyle,
       CursorAlignOnScroll = CursorAlignOnScroll::kIfNeeded);
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
index 247820ff..eafe272 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -171,7 +171,7 @@
           .Extend(PositionInFlatTree(GetDocument().body(), 2))
           .Build());
   Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                     kWordGranularity);
+                     TextGranularity::kWord);
   EXPECT_EQ(Position(two, 0), VisibleSelectionInDOMTree().Start());
   EXPECT_EQ(Position(two, 3), VisibleSelectionInDOMTree().End());
   EXPECT_EQ(PositionInFlatTree(two, 0),
@@ -186,9 +186,9 @@
   Selection().SetSelection(
       SelectionInDOMTree::Builder().Collapse(end_of_text).Build());
 
-  EXPECT_FALSE(Selection().Modify(FrameSelection::kAlterationMove,
-                                  kDirectionForward, kCharacterGranularity,
-                                  kNotUserTriggered))
+  EXPECT_FALSE(
+      Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
+                         TextGranularity::kCharacter, kNotUserTriggered))
       << "Selection.modify() returns false for non-user-triggered call when "
          "selection isn't modified.";
   EXPECT_EQ(end_of_text,
@@ -196,7 +196,7 @@
       << "Selection isn't modified";
 
   EXPECT_TRUE(Selection().Modify(FrameSelection::kAlterationMove,
-                                 kDirectionForward, kCharacterGranularity,
+                                 kDirectionForward, TextGranularity::kCharacter,
                                  kUserTriggered))
       << "Selection.modify() returns true for user-triggered call";
   EXPECT_EQ(end_of_text,
@@ -219,22 +219,22 @@
   // "Foo B|ar B>az," with the Character granularity.
   Selection().MoveRangeSelection(CreateVisiblePosition(Position(text, 5)),
                                  CreateVisiblePosition(Position(text, 9)),
-                                 kCharacterGranularity);
+                                 TextGranularity::kCharacter);
   EXPECT_EQ_SELECTED_TEXT("ar B");
   // "Foo B|ar B>az," with the Word granularity.
   Selection().MoveRangeSelection(CreateVisiblePosition(Position(text, 5)),
                                  CreateVisiblePosition(Position(text, 9)),
-                                 kWordGranularity);
+                                 TextGranularity::kWord);
   EXPECT_EQ_SELECTED_TEXT("Bar Baz");
   // "Fo<o B|ar Baz," with the Character granularity.
   Selection().MoveRangeSelection(CreateVisiblePosition(Position(text, 5)),
                                  CreateVisiblePosition(Position(text, 2)),
-                                 kCharacterGranularity);
+                                 TextGranularity::kCharacter);
   EXPECT_EQ_SELECTED_TEXT("o B");
   // "Fo<o B|ar Baz," with the Word granularity.
   Selection().MoveRangeSelection(CreateVisiblePosition(Position(text, 5)),
                                  CreateVisiblePosition(Position(text, 2)),
-                                 kWordGranularity);
+                                 TextGranularity::kWord);
   EXPECT_EQ_SELECTED_TEXT("Foo Bar");
 }
 
@@ -245,7 +245,7 @@
   Selection().MoveRangeSelection(
       CreateVisiblePosition(Position(sample->firstChild(), 1)),
       CreateVisiblePosition(Position(sample->firstChild(), 1)),
-      kWordGranularity);
+      TextGranularity::kWord);
   EXPECT_EQ("xyz", Selection().SelectedText());
   sample->insertBefore(Text::Create(GetDocument(), "abc"),
                        sample->firstChild());
diff --git a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
index cb515b81..98b560d 100644
--- a/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
+++ b/third_party/WebKit/Source/core/editing/GranularityStrategy.cpp
@@ -82,7 +82,7 @@
 
 DirectionGranularityStrategy::DirectionGranularityStrategy()
     : state_(StrategyState::kCleared),
-      granularity_(kCharacterGranularity),
+      granularity_(TextGranularity::kCharacter),
       offset_(0) {}
 
 DirectionGranularityStrategy::~DirectionGranularityStrategy() {}
@@ -93,7 +93,7 @@
 
 void DirectionGranularityStrategy::Clear() {
   state_ = StrategyState::kCleared;
-  granularity_ = kCharacterGranularity;
+  granularity_ = TextGranularity::kCharacter;
   offset_ = 0;
   diff_extent_point_from_extent_position_ = IntSize();
 }
@@ -137,7 +137,7 @@
   bool vertical_change = new_offset_location.Y() != old_extent_location.Y();
   if (vertical_change) {
     offset_ = 0;
-    granularity_ = kCharacterGranularity;
+    granularity_ = TextGranularity::kCharacter;
     new_offset_extent_point = extent_point;
     new_offset_extent_position =
         VisiblePositionForContentsPoint(extent_point, frame);
@@ -169,7 +169,7 @@
   bool this_move_shrunk_selection;
   if (new_offset_extent_position.DeepEquivalent() ==
       old_offset_extent_position.DeepEquivalent()) {
-    if (granularity_ == kCharacterGranularity)
+    if (granularity_ == TextGranularity::kCharacter)
       return selection.AsSelection();
 
     // If we are in Word granularity, we cannot exit here, since we may pass
@@ -203,7 +203,7 @@
                                         ? SearchDirection::kSearchForward
                                         : SearchDirection::kSearchBackwards,
                                     BoundAdjust::kNextBoundIfOnBound);
-      granularity_ = kCharacterGranularity;
+      granularity_ = TextGranularity::kCharacter;
     } else {
       // Calculate the word boundary based on |oldExtentWithGranularity|.
       // If selection was shrunk in the last update and the extent is now
@@ -234,13 +234,13 @@
         !extent_base_order_switched && !selection_expanded;
 
     if (expanded_beyond_word_boundary)
-      granularity_ = kWordGranularity;
+      granularity_ = TextGranularity::kWord;
     else if (this_move_shrunk_selection)
-      granularity_ = kCharacterGranularity;
+      granularity_ = TextGranularity::kCharacter;
   }
 
   VisiblePosition new_selection_extent = new_offset_extent_position;
-  if (granularity_ == kWordGranularity) {
+  if (granularity_ == TextGranularity::kWord) {
     // Determine the bounds of the word where the extent is located.
     // Set the selection extent to one of the two bounds depending on
     // whether the extent is passed the middle of the word.
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index e9793de1..b314ef6 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -284,8 +284,8 @@
       if (!this->Selection().IsHandleVisible()) {
         const bool did_select =
             UpdateSelectionForMouseDownDispatchingSelectStart(
-                inner_node, selection.AsSelection(), kCharacterGranularity,
-                HandleVisibility::kVisible);
+                inner_node, selection.AsSelection(),
+                TextGranularity::kCharacter, HandleVisibility::kVisible);
         if (did_select) {
           frame_->GetEventHandler().ShowNonLocatedContextMenu(nullptr,
                                                               kMenuSourceTouch);
@@ -319,14 +319,14 @@
 
   if (selection_state_ == SelectionState::kExtendedSelection) {
     UpdateSelectionForMouseDownDispatchingSelectStart(
-        inner_node, selection.AsSelection(), kCharacterGranularity,
+        inner_node, selection.AsSelection(), TextGranularity::kCharacter,
         HandleVisibility::kNotVisible);
     return false;
   }
 
   if (visible_pos.IsNull()) {
     UpdateSelectionForMouseDownDispatchingSelectStart(
-        inner_node, SelectionInFlatTree(), kCharacterGranularity,
+        inner_node, SelectionInFlatTree(), TextGranularity::kCharacter,
         HandleVisibility::kNotVisible);
     return false;
   }
@@ -351,7 +351,7 @@
                           SelectionInFlatTree::Builder()
                               .Collapse(visible_pos.ToPositionWithAffinity())
                               .Build())),
-      kCharacterGranularity,
+      TextGranularity::kCharacter,
       is_handle_visible ? HandleVisibility::kVisible
                         : HandleVisibility::kNotVisible);
   return false;
@@ -476,7 +476,7 @@
   }
 
   selection_state_ = SelectionState::kPlacedCaret;
-  SetNonDirectionalSelectionIfNeeded(selection, kCharacterGranularity,
+  SetNonDirectionalSelectionIfNeeded(selection, TextGranularity::kCharacter,
                                      kDoNotAdjustEndpoints, handle_visibility);
   return true;
 }
@@ -508,7 +508,7 @@
                             SelectionInFlatTree::Builder()
                                 .Collapse(pos.ToPositionWithAffinity())
                                 .Build(),
-                            kWordGranularity)
+                            TextGranularity::kWord)
                       : VisibleSelectionInFlatTree();
 
   HandleVisibility visibility = HandleVisibility::kNotVisible;
@@ -541,7 +541,7 @@
   return UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
       ExpandSelectionToRespectUserSelectAll(inner_node, adjusted_selection),
-      kWordGranularity, visibility);
+      TextGranularity::kWord, visibility);
 }
 
 void SelectionController::SelectClosestMisspellingFromHitTestResult(
@@ -555,7 +555,7 @@
   const VisiblePositionInFlatTree& pos = VisiblePositionOfHitTestResult(result);
   if (pos.IsNull()) {
     UpdateSelectionForMouseDownDispatchingSelectStart(
-        inner_node, SelectionInFlatTree(), kWordGranularity,
+        inner_node, SelectionInFlatTree(), TextGranularity::kWord,
         HandleVisibility::kNotVisible);
     return;
   }
@@ -568,7 +568,7 @@
           DocumentMarker::MisspellingMarkers());
   if (!marker) {
     UpdateSelectionForMouseDownDispatchingSelectStart(
-        inner_node, SelectionInFlatTree(), kWordGranularity,
+        inner_node, SelectionInFlatTree(), TextGranularity::kWord,
         HandleVisibility::kNotVisible);
     return;
   }
@@ -585,7 +585,7 @@
   UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
       ExpandSelectionToRespectUserSelectAll(inner_node, adjusted_selection),
-      kWordGranularity, HandleVisibility::kNotVisible);
+      TextGranularity::kWord, HandleVisibility::kNotVisible);
 }
 
 bool SelectionController::SelectClosestWordFromMouseEvent(
@@ -647,7 +647,7 @@
   UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
       ExpandSelectionToRespectUserSelectAll(inner_node, new_selection),
-      kWordGranularity, HandleVisibility::kNotVisible);
+      TextGranularity::kWord, HandleVisibility::kNotVisible);
 }
 
 static SelectionInFlatTree AdjustEndpointsAtBidiBoundary(
@@ -802,7 +802,7 @@
 
   if (visible_pos.IsNull()) {
     UpdateSelectionForMouseDownDispatchingSelectStart(
-        inner_node, SelectionInFlatTree(), kCharacterGranularity,
+        inner_node, SelectionInFlatTree(), TextGranularity::kCharacter,
         HandleVisibility::kVisible);
     return;
   }
@@ -813,7 +813,7 @@
                           SelectionInFlatTree::Builder()
                               .Collapse(visible_pos.ToPositionWithAffinity())
                               .Build())),
-      kCharacterGranularity, HandleVisibility::kVisible);
+      TextGranularity::kCharacter, HandleVisibility::kVisible);
 }
 
 bool SelectionController::HandleDoubleClick(
@@ -876,7 +876,7 @@
                             SelectionInFlatTree::Builder()
                                 .Collapse(pos.ToPositionWithAffinity())
                                 .Build(),
-                            kParagraphGranularity)
+                            TextGranularity::kParagraph)
                       : VisibleSelectionInFlatTree();
 
   const bool is_handle_visible =
@@ -885,7 +885,7 @@
   const bool did_select = UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
       ExpandSelectionToRespectUserSelectAll(inner_node, new_selection),
-      kParagraphGranularity,
+      TextGranularity::kParagraph,
       is_handle_visible ? HandleVisibility::kVisible
                         : HandleVisibility::kNotVisible);
   if (!did_select)
diff --git a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
index 0731193..421bd064 100644
--- a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
@@ -65,7 +65,7 @@
                                          .Collapse(PositionInFlatTree(top, 1))
                                          .Extend(PositionInFlatTree(bottom, 3))
                                          .Build(),
-                                     kCharacterGranularity);
+                                     TextGranularity::kCharacter);
   EXPECT_EQ(Position(top, 1), VisibleSelectionInDOMTree().Base());
   EXPECT_EQ(Position::BeforeNode(*host), VisibleSelectionInDOMTree().Extent());
   EXPECT_EQ(Position(top, 1), VisibleSelectionInDOMTree().Start());
@@ -85,7 +85,7 @@
           .Collapse(PositionInFlatTree(bottom, 3))
           .Extend(PositionInFlatTree(top, 1))
           .Build(),
-      kCharacterGranularity);
+      TextGranularity::kCharacter);
   EXPECT_EQ(Position(bottom, 3), VisibleSelectionInDOMTree().Base());
   EXPECT_EQ(Position::BeforeNode(*bottom->parentNode()),
             VisibleSelectionInDOMTree().Extent());
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
index dbb85e8..4446a2a 100644
--- a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
@@ -210,30 +210,30 @@
   // block is LTR direction, but it extends backward logically if the enclosing
   // block is RTL direction.
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = NextPositionOf(pos, kCanSkipOverEditingBoundary);
       else
         pos = PreviousPositionOf(pos, kCanSkipOverEditingBoundary);
       break;
-    case kWordGranularity:
+    case TextGranularity::kWord:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = NextWordPositionForPlatform(pos);
       else
         pos = PreviousWordPosition(pos);
       break;
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = ModifyExtendingForward(granularity);
       else
         pos = ModifyExtendingBackward(granularity);
       break;
-    case kSentenceGranularity:
-    case kLineGranularity:
-    case kParagraphGranularity:
-    case kSentenceBoundary:
-    case kParagraphBoundary:
-    case kDocumentBoundary:
+    case TextGranularity::kSentence:
+    case TextGranularity::kLine:
+    case TextGranularity::kParagraph:
+    case TextGranularity::kSentenceBoundary:
+    case TextGranularity::kParagraphBoundary:
+    case TextGranularity::kDocumentBoundary:
       // FIXME: implement all of the above?
       pos = ModifyExtendingForward(granularity);
       break;
@@ -248,34 +248,34 @@
   VisiblePosition pos =
       CreateVisiblePosition(selection_.Extent(), selection_.Affinity());
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       pos = NextPositionOf(pos, kCanSkipOverEditingBoundary);
       break;
-    case kWordGranularity:
+    case TextGranularity::kWord:
       pos = NextWordPositionForPlatform(pos);
       break;
-    case kSentenceGranularity:
+    case TextGranularity::kSentence:
       pos = NextSentencePosition(pos);
       break;
-    case kLineGranularity:
+    case TextGranularity::kLine:
       pos = NextLinePosition(pos, LineDirectionPointForBlockDirectionNavigation(
                                       selection_.Extent()));
       break;
-    case kParagraphGranularity:
+    case TextGranularity::kParagraph:
       pos = NextParagraphPosition(
           pos,
           LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
       break;
-    case kSentenceBoundary:
+    case TextGranularity::kSentenceBoundary:
       pos = EndOfSentence(EndForPlatform());
       break;
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       pos = LogicalEndOfLine(EndForPlatform());
       break;
-    case kParagraphBoundary:
+    case TextGranularity::kParagraphBoundary:
       pos = EndOfParagraph(EndForPlatform());
       break;
-    case kDocumentBoundary:
+    case TextGranularity::kDocumentBoundary:
       pos = EndForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent()))
         pos = EndOfEditableContent(pos);
@@ -291,7 +291,7 @@
 VisiblePosition SelectionModifier::ModifyMovingRight(
     TextGranularity granularity) {
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (!selection_.IsRange()) {
         return RightPositionOf(
             CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
@@ -299,7 +299,7 @@
       if (DirectionOfSelection() == TextDirection::kLtr)
         return CreateVisiblePosition(selection_.End(), selection_.Affinity());
       return CreateVisiblePosition(selection_.Start(), selection_.Affinity());
-    case kWordGranularity: {
+    case TextGranularity::kWord: {
       const bool skips_space_when_moving_right =
           GetFrame() &&
           GetFrame()->GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight();
@@ -307,78 +307,69 @@
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
           skips_space_when_moving_right);
     }
-    case kSentenceGranularity:
-    case kLineGranularity:
-    case kParagraphGranularity:
-    case kSentenceBoundary:
-    case kParagraphBoundary:
-    case kDocumentBoundary:
+    case TextGranularity::kSentence:
+    case TextGranularity::kLine:
+    case TextGranularity::kParagraph:
+    case TextGranularity::kSentenceBoundary:
+    case TextGranularity::kParagraphBoundary:
+    case TextGranularity::kDocumentBoundary:
       // TODO(editing-dev): Implement all of the above.
       return ModifyMovingForward(granularity);
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       return RightBoundaryOfLine(StartForPlatform(),
                                  DirectionOfEnclosingBlock());
   }
-  NOTREACHED() << granularity;
+  NOTREACHED() << static_cast<int>(granularity);
   return VisiblePosition();
 }
 
 VisiblePosition SelectionModifier::ModifyMovingForward(
     TextGranularity granularity) {
-  VisiblePosition pos;
-  // FIXME: Stay in editable content for the less common granularities.
+  // TODO(editing-dev): Stay in editable content for the less common
+  // granularities.
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (selection_.IsRange())
-        pos = CreateVisiblePosition(selection_.End(), selection_.Affinity());
-      else
-        pos = NextPositionOf(
-            CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
-            kCanSkipOverEditingBoundary);
-      break;
-    case kWordGranularity:
-      pos = NextWordPositionForPlatform(
+        return CreateVisiblePosition(selection_.End(), selection_.Affinity());
+      return NextPositionOf(
+          CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
+          kCanSkipOverEditingBoundary);
+    case TextGranularity::kWord:
+      return NextWordPositionForPlatform(
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
-      break;
-    case kSentenceGranularity:
-      pos = NextSentencePosition(
+    case TextGranularity::kSentence:
+      return NextSentencePosition(
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
-      break;
-    case kLineGranularity: {
+    case TextGranularity::kLine: {
       // down-arrowing from a range selection that ends at the start of a line
       // needs to leave the selection at that line start (no need to call
       // nextLinePosition!)
-      pos = EndForPlatform();
-      if (!selection_.IsRange() || !IsStartOfLine(pos)) {
-        pos = NextLinePosition(
-            pos,
-            LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
-      }
-      break;
+      const VisiblePosition& pos = EndForPlatform();
+      if (selection_.IsRange() && IsStartOfLine(pos))
+        return pos;
+      return NextLinePosition(
+          pos,
+          LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
     }
-    case kParagraphGranularity:
-      pos = NextParagraphPosition(
+    case TextGranularity::kParagraph:
+      return NextParagraphPosition(
           EndForPlatform(),
           LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
-      break;
-    case kSentenceBoundary:
-      pos = EndOfSentence(EndForPlatform());
-      break;
-    case kLineBoundary:
-      pos = LogicalEndOfLine(EndForPlatform());
-      break;
-    case kParagraphBoundary:
-      pos = EndOfParagraph(EndForPlatform());
-      break;
-    case kDocumentBoundary:
-      pos = EndForPlatform();
+    case TextGranularity::kSentenceBoundary:
+      return EndOfSentence(EndForPlatform());
+    case TextGranularity::kLineBoundary:
+      return LogicalEndOfLine(EndForPlatform());
+    case TextGranularity::kParagraphBoundary:
+      return EndOfParagraph(EndForPlatform());
+    case TextGranularity::kDocumentBoundary: {
+      const VisiblePosition& pos = EndForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent()))
-        pos = EndOfEditableContent(pos);
-      else
-        pos = EndOfDocument(pos);
-      break;
+        return EndOfEditableContent(pos);
+      return EndOfDocument(pos);
+    }
   }
-  return pos;
+  NOTREACHED() << static_cast<int>(granularity);
+  return VisiblePosition();
 }
 
 VisiblePosition SelectionModifier::ModifyExtendingLeft(
@@ -393,30 +384,30 @@
   // block is LTR direction, but it extends forward logically if the enclosing
   // block is RTL direction.
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = PreviousPositionOf(pos, kCanSkipOverEditingBoundary);
       else
         pos = NextPositionOf(pos, kCanSkipOverEditingBoundary);
       break;
-    case kWordGranularity:
+    case TextGranularity::kWord:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = PreviousWordPosition(pos);
       else
         pos = NextWordPositionForPlatform(pos);
       break;
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
         pos = ModifyExtendingBackward(granularity);
       else
         pos = ModifyExtendingForward(granularity);
       break;
-    case kSentenceGranularity:
-    case kLineGranularity:
-    case kParagraphGranularity:
-    case kSentenceBoundary:
-    case kParagraphBoundary:
-    case kDocumentBoundary:
+    case TextGranularity::kSentence:
+    case TextGranularity::kLine:
+    case TextGranularity::kParagraph:
+    case TextGranularity::kSentenceBoundary:
+    case TextGranularity::kParagraphBoundary:
+    case TextGranularity::kDocumentBoundary:
       pos = ModifyExtendingBackward(granularity);
       break;
   }
@@ -435,35 +426,35 @@
   // deleting. It was done here instead of in VisiblePosition because we want
   // VPs to iterate over everything.
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       pos = PreviousPositionOf(pos, kCanSkipOverEditingBoundary);
       break;
-    case kWordGranularity:
+    case TextGranularity::kWord:
       pos = PreviousWordPosition(pos);
       break;
-    case kSentenceGranularity:
+    case TextGranularity::kSentence:
       pos = PreviousSentencePosition(pos);
       break;
-    case kLineGranularity:
+    case TextGranularity::kLine:
       pos = PreviousLinePosition(
           pos,
           LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
       break;
-    case kParagraphGranularity:
+    case TextGranularity::kParagraph:
       pos = PreviousParagraphPosition(
           pos,
           LineDirectionPointForBlockDirectionNavigation(selection_.Extent()));
       break;
-    case kSentenceBoundary:
+    case TextGranularity::kSentenceBoundary:
       pos = StartOfSentence(StartForPlatform());
       break;
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       pos = LogicalStartOfLine(StartForPlatform());
       break;
-    case kParagraphBoundary:
+    case TextGranularity::kParagraphBoundary:
       pos = StartOfParagraph(StartForPlatform());
       break;
-    case kDocumentBoundary:
+    case TextGranularity::kDocumentBoundary:
       pos = StartForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent()))
         pos = StartOfEditableContent(pos);
@@ -479,7 +470,7 @@
 VisiblePosition SelectionModifier::ModifyMovingLeft(
     TextGranularity granularity) {
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (!selection_.IsRange()) {
         return LeftPositionOf(
             CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
@@ -487,7 +478,7 @@
       if (DirectionOfSelection() == TextDirection::kLtr)
         return CreateVisiblePosition(selection_.Start(), selection_.Affinity());
       return CreateVisiblePosition(selection_.End(), selection_.Affinity());
-    case kWordGranularity: {
+    case TextGranularity::kWord: {
       const bool skips_space_when_moving_right =
           GetFrame() &&
           GetFrame()->GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight();
@@ -495,19 +486,19 @@
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
           skips_space_when_moving_right);
     }
-    case kSentenceGranularity:
-    case kLineGranularity:
-    case kParagraphGranularity:
-    case kSentenceBoundary:
-    case kParagraphBoundary:
-    case kDocumentBoundary:
+    case TextGranularity::kSentence:
+    case TextGranularity::kLine:
+    case TextGranularity::kParagraph:
+    case TextGranularity::kSentenceBoundary:
+    case TextGranularity::kParagraphBoundary:
+    case TextGranularity::kDocumentBoundary:
       // FIXME: Implement all of the above.
       return ModifyMovingBackward(granularity);
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       return LeftBoundaryOfLine(StartForPlatform(),
                                 DirectionOfEnclosingBlock());
   }
-  NOTREACHED() << granularity;
+  NOTREACHED() << static_cast<int>(granularity);
   return VisiblePosition();
 }
 
@@ -515,7 +506,7 @@
     TextGranularity granularity) {
   VisiblePosition pos;
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       if (selection_.IsRange())
         pos = CreateVisiblePosition(selection_.Start(), selection_.Affinity());
       else
@@ -523,34 +514,34 @@
             CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
             kCanSkipOverEditingBoundary);
       break;
-    case kWordGranularity:
+    case TextGranularity::kWord:
       pos = PreviousWordPosition(
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
       break;
-    case kSentenceGranularity:
+    case TextGranularity::kSentence:
       pos = PreviousSentencePosition(
           CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
       break;
-    case kLineGranularity:
+    case TextGranularity::kLine:
       pos = PreviousLinePosition(
           StartForPlatform(),
           LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
       break;
-    case kParagraphGranularity:
+    case TextGranularity::kParagraph:
       pos = PreviousParagraphPosition(
           StartForPlatform(),
           LineDirectionPointForBlockDirectionNavigation(selection_.Start()));
       break;
-    case kSentenceBoundary:
+    case TextGranularity::kSentenceBoundary:
       pos = StartOfSentence(StartForPlatform());
       break;
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       pos = LogicalStartOfLine(StartForPlatform());
       break;
-    case kParagraphBoundary:
+    case TextGranularity::kParagraphBoundary:
       pos = StartOfParagraph(StartForPlatform());
       break;
-    case kDocumentBoundary:
+    case TextGranularity::kDocumentBoundary:
       pos = StartForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent()))
         pos = StartOfEditableContent(pos);
@@ -562,8 +553,9 @@
 }
 
 static bool IsBoundary(TextGranularity granularity) {
-  return granularity == kLineBoundary || granularity == kParagraphBoundary ||
-         granularity == kDocumentBoundary;
+  return granularity == TextGranularity::kLineBoundary ||
+         granularity == TextGranularity::kParagraphBoundary ||
+         granularity == TextGranularity::kDocumentBoundary;
 }
 
 bool SelectionModifier::Modify(EAlteration alter,
@@ -636,9 +628,9 @@
     case FrameSelection::kAlterationExtend:
 
       if (!selection_.IsCaret() &&
-          (granularity == kWordGranularity ||
-           granularity == kParagraphGranularity ||
-           granularity == kLineGranularity) &&
+          (granularity == TextGranularity::kWord ||
+           granularity == TextGranularity::kParagraph ||
+           granularity == TextGranularity::kLine) &&
           GetFrame() &&
           !GetFrame()
                ->GetEditor()
@@ -702,7 +694,8 @@
       break;
   }
 
-  if (granularity == kLineGranularity || granularity == kParagraphGranularity)
+  if (granularity == TextGranularity::kLine ||
+      granularity == TextGranularity::kParagraph)
     x_pos_for_vertical_arrow_navigation_ = x;
 
   return true;
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp b/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
index 06efd7f..aac91864 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
@@ -79,13 +79,13 @@
 template <typename Strategy>
 bool SelectionTemplate<Strategy>::IsCaret() const {
   return base_.IsNotNull() && base_ == extent_ &&
-         granularity_ == kCharacterGranularity;
+         granularity_ == TextGranularity::kCharacter;
 }
 
 template <typename Strategy>
 bool SelectionTemplate<Strategy>::IsRange() const {
   return base_ != extent_ ||
-         (base_.IsNotNull() && granularity_ != kCharacterGranularity);
+         (base_.IsNotNull() && granularity_ != TextGranularity::kCharacter);
 }
 
 template <typename Strategy>
@@ -159,7 +159,7 @@
     const {
   if (base_.IsNull())
     return kNoSelection;
-  if (base_ == extent_ && granularity_ == kCharacterGranularity)
+  if (base_ == extent_ && granularity_ == TextGranularity::kCharacter)
     return kCaretSelection;
   return kRangeSelection;
 }
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplate.h b/third_party/WebKit/Source/core/editing/SelectionTemplate.h
index 52302d4..73adfec 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplate.h
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplate.h
@@ -122,7 +122,7 @@
   PositionTemplate<Strategy> base_;
   PositionTemplate<Strategy> extent_;
   TextAffinity affinity_ = TextAffinity::kDownstream;
-  TextGranularity granularity_ = kCharacterGranularity;
+  TextGranularity granularity_ = TextGranularity::kCharacter;
   bool is_directional_ = false;
   bool is_handle_visible_ = false;
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp b/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
index 6d7e6f6..ce1b3003 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
@@ -15,7 +15,7 @@
   SelectionInDOMTree selection;
 
   EXPECT_EQ(TextAffinity::kDownstream, selection.Affinity());
-  EXPECT_EQ(kCharacterGranularity, selection.Granularity());
+  EXPECT_EQ(TextGranularity::kCharacter, selection.Granularity());
   EXPECT_FALSE(selection.IsDirectional());
   EXPECT_FALSE(selection.IsHandleVisible());
   EXPECT_TRUE(selection.IsNone());
@@ -33,7 +33,7 @@
   const SelectionInDOMTree& selection = builder.Build();
 
   EXPECT_EQ(TextAffinity::kDownstream, selection.Affinity());
-  EXPECT_EQ(kCharacterGranularity, selection.Granularity());
+  EXPECT_EQ(TextGranularity::kCharacter, selection.Granularity());
   EXPECT_FALSE(selection.IsDirectional());
   EXPECT_FALSE(selection.IsHandleVisible());
   EXPECT_FALSE(selection.IsNone());
@@ -53,7 +53,7 @@
   const SelectionInDOMTree& selection = builder.Build();
 
   EXPECT_EQ(TextAffinity::kDownstream, selection.Affinity());
-  EXPECT_EQ(kCharacterGranularity, selection.Granularity());
+  EXPECT_EQ(TextGranularity::kCharacter, selection.Granularity());
   EXPECT_FALSE(selection.IsDirectional());
   EXPECT_FALSE(selection.IsHandleVisible());
   EXPECT_FALSE(selection.IsNone());
diff --git a/third_party/WebKit/Source/core/editing/TextGranularity.h b/third_party/WebKit/Source/core/editing/TextGranularity.h
index f839ec7..f0f868b 100644
--- a/third_party/WebKit/Source/core/editing/TextGranularity.h
+++ b/third_party/WebKit/Source/core/editing/TextGranularity.h
@@ -30,12 +30,12 @@
 
 // FIXME: This really should be broken up into more than one concept.
 // LocalFrame doesn't need the 3 boundaries in this enum.
-enum TextGranularity {
-  kCharacterGranularity,
-  kWordGranularity,
-  kSentenceGranularity,
-  kLineGranularity,
-  kParagraphGranularity,
+enum class TextGranularity {
+  kCharacter,
+  kWord,
+  kSentence,
+  kLine,
+  kParagraph,
   kSentenceBoundary,
   kLineBoundary,
   kParagraphBoundary,
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index 9cc7ccdb..71aef32 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -45,8 +45,7 @@
     : affinity_(TextAffinity::kDownstream),
       selection_type_(kNoSelection),
       base_is_first_(true),
-      is_directional_(false),
-      granularity_(kCharacterGranularity) {}
+      is_directional_(false) {}
 
 template <typename Strategy>
 VisibleSelectionTemplate<Strategy>::VisibleSelectionTemplate(
@@ -56,9 +55,8 @@
       extent_(selection.Extent()),
       affinity_(selection.Affinity()),
       selection_type_(kNoSelection),
-      is_directional_(selection.IsDirectional()),
-      granularity_(granularity) {
-  Validate(granularity_);
+      is_directional_(selection.IsDirectional()) {
+  Validate(granularity);
 }
 
 template <typename Strategy>
@@ -123,8 +121,7 @@
       affinity_(other.affinity_),
       selection_type_(other.selection_type_),
       base_is_first_(other.base_is_first_),
-      is_directional_(other.is_directional_),
-      granularity_(other.granularity_) {}
+      is_directional_(other.is_directional_) {}
 
 template <typename Strategy>
 VisibleSelectionTemplate<Strategy>& VisibleSelectionTemplate<Strategy>::
@@ -137,7 +134,6 @@
   selection_type_ = other.selection_type_;
   base_is_first_ = other.base_is_first_;
   is_directional_ = other.is_directional_;
-  granularity_ = other.granularity_;
   return *this;
 }
 
@@ -200,7 +196,6 @@
 VisibleSelectionTemplate<Strategy>::AppendTrailingWhitespace() const {
   if (IsNone())
     return *this;
-  DCHECK_EQ(granularity_, kWordGranularity);
   if (!IsRange())
     return *this;
   const PositionTemplate<Strategy>& new_end = SkipWhitespace(end_);
@@ -244,10 +239,10 @@
   DCHECK(passed_start.IsNotNull());
 
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       // Don't do any expansion.
       return passed_start.GetPosition();
-    case kWordGranularity: {
+    case TextGranularity::kWord: {
       // General case: Select the word the caret is positioned inside of.
       // If the caret is on the word boundary, select the word according to
       // |wordSide|.
@@ -268,27 +263,27 @@
       return StartOfWord(visible_start, kRightWordIfOnBoundary)
           .DeepEquivalent();
     }
-    case kSentenceGranularity:
+    case TextGranularity::kSentence:
       return StartOfSentence(CreateVisiblePosition(passed_start))
           .DeepEquivalent();
-    case kLineGranularity:
+    case TextGranularity::kLine:
       return StartOfLine(CreateVisiblePosition(passed_start)).DeepEquivalent();
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       return StartOfLine(CreateVisiblePosition(passed_start)).DeepEquivalent();
-    case kParagraphGranularity: {
+    case TextGranularity::kParagraph: {
       const VisiblePositionTemplate<Strategy> pos =
           CreateVisiblePosition(passed_start);
       if (IsStartOfLine(pos) && IsEndOfEditableOrNonEditableContent(pos))
         return StartOfParagraph(PreviousPositionOf(pos)).DeepEquivalent();
       return StartOfParagraph(pos).DeepEquivalent();
     }
-    case kDocumentBoundary:
+    case TextGranularity::kDocumentBoundary:
       return StartOfDocument(CreateVisiblePosition(passed_start))
           .DeepEquivalent();
-    case kParagraphBoundary:
+    case TextGranularity::kParagraphBoundary:
       return StartOfParagraph(CreateVisiblePosition(passed_start))
           .DeepEquivalent();
-    case kSentenceBoundary:
+    case TextGranularity::kSentenceBoundary:
       return StartOfSentence(CreateVisiblePosition(passed_start))
           .DeepEquivalent();
   }
@@ -317,10 +312,10 @@
   DCHECK(passed_end.IsNotNull());
 
   switch (granularity) {
-    case kCharacterGranularity:
+    case TextGranularity::kCharacter:
       // Don't do any expansion.
       return passed_end.GetPosition();
-    case kWordGranularity: {
+    case TextGranularity::kWord: {
       // General case: Select the word the caret is positioned inside of.
       // If the caret is on the word boundary, select the word according to
       // |wordSide|.
@@ -367,9 +362,9 @@
         return word_end.DeepEquivalent();
       return next.DeepEquivalent();
     }
-    case kSentenceGranularity:
+    case TextGranularity::kSentence:
       return EndOfSentence(CreateVisiblePosition(passed_end)).DeepEquivalent();
-    case kLineGranularity: {
+    case TextGranularity::kLine: {
       const VisiblePositionTemplate<Strategy> end =
           EndOfLine(CreateVisiblePosition(passed_end));
       if (!IsEndOfParagraph(end))
@@ -381,9 +376,9 @@
         return end.DeepEquivalent();
       return next.DeepEquivalent();
     }
-    case kLineBoundary:
+    case TextGranularity::kLineBoundary:
       return EndOfLine(CreateVisiblePosition(passed_end)).DeepEquivalent();
-    case kParagraphGranularity: {
+    case TextGranularity::kParagraph: {
       const VisiblePositionTemplate<Strategy> visible_paragraph_end =
           EndOfParagraph(CreateVisiblePosition(passed_end));
 
@@ -414,11 +409,11 @@
         return visible_paragraph_end.DeepEquivalent();
       return next.DeepEquivalent();
     }
-    case kDocumentBoundary:
+    case TextGranularity::kDocumentBoundary:
       return EndOfDocument(CreateVisiblePosition(passed_end)).DeepEquivalent();
-    case kParagraphBoundary:
+    case TextGranularity::kParagraphBoundary:
       return EndOfParagraph(CreateVisiblePosition(passed_end)).DeepEquivalent();
-    case kSentenceBoundary:
+    case TextGranularity::kSentenceBoundary:
       return EndOfSentence(CreateVisiblePosition(passed_end)).DeepEquivalent();
   }
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h
index 665889c..9ff23f03 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.h
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -152,7 +152,7 @@
 
   VisibleSelectionTemplate(const SelectionTemplate<Strategy>&, TextGranularity);
 
-  void Validate(TextGranularity = kCharacterGranularity);
+  void Validate(TextGranularity = TextGranularity::kCharacter);
 
   // Support methods for validate()
   void SetBaseAndExtentToDeepEquivalents();
@@ -182,8 +182,6 @@
   // Non-directional ignores m_baseIsFirst and selection always extends on shift
   // + arrow key.
   bool is_directional_ : 1;
-
-  TextGranularity granularity_;
 };
 
 extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp b/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
index 2132da9..e7c66cc 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
@@ -87,7 +87,7 @@
           .Collapse(Position::BeforeNode(*input))
           .Extend(Position::AfterNode(*input))
           .Build(),
-      kWordGranularity);
+      TextGranularity::kWord);
   const VisibleSelection result = selection.AppendTrailingWhitespace();
 
   EXPECT_EQ(Position::BeforeNode(*input), result.Start());
@@ -116,13 +116,13 @@
   // From a position at distributed node
   selection = CreateVisibleSelection(
       SelectionInDOMTree::Builder().Collapse(Position(one, 1)).Build());
-  selection = ExpandUsingGranularity(selection, kWordGranularity);
+  selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
   selection_in_flat_tree =
       CreateVisibleSelection(SelectionInFlatTree::Builder()
                                  .Collapse(PositionInFlatTree(one, 1))
                                  .Build());
   selection_in_flat_tree =
-      ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+      ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
   EXPECT_EQ(Position(one, 1), selection.Base());
   EXPECT_EQ(Position(one, 1), selection.Extent());
@@ -137,13 +137,13 @@
   // From a position at distributed node
   selection = CreateVisibleSelection(
       SelectionInDOMTree::Builder().Collapse(Position(two, 1)).Build());
-  selection = ExpandUsingGranularity(selection, kWordGranularity);
+  selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
   selection_in_flat_tree =
       CreateVisibleSelection(SelectionInFlatTree::Builder()
                                  .Collapse(PositionInFlatTree(two, 1))
                                  .Build());
   selection_in_flat_tree =
-      ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+      ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
   EXPECT_EQ(Position(two, 1), selection.Base());
   EXPECT_EQ(Position(two, 1), selection.Extent());
@@ -158,13 +158,13 @@
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
       SelectionInDOMTree::Builder().Collapse(Position(three, 1)).Build());
-  selection = ExpandUsingGranularity(selection, kWordGranularity);
+  selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
   selection_in_flat_tree =
       CreateVisibleSelection(SelectionInFlatTree::Builder()
                                  .Collapse(PositionInFlatTree(three, 1))
                                  .Build());
   selection_in_flat_tree =
-      ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+      ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
   EXPECT_EQ(Position(three, 1), selection.Base());
   EXPECT_EQ(Position(three, 1), selection.Extent());
@@ -179,13 +179,13 @@
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
       SelectionInDOMTree::Builder().Collapse(Position(four, 1)).Build());
-  selection = ExpandUsingGranularity(selection, kWordGranularity);
+  selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
   selection_in_flat_tree =
       CreateVisibleSelection(SelectionInFlatTree::Builder()
                                  .Collapse(PositionInFlatTree(four, 1))
                                  .Build());
   selection_in_flat_tree =
-      ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+      ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
   EXPECT_EQ(Position(four, 1), selection.Base());
   EXPECT_EQ(Position(four, 1), selection.Extent());
@@ -200,13 +200,13 @@
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
       SelectionInDOMTree::Builder().Collapse(Position(five, 1)).Build());
-  selection = ExpandUsingGranularity(selection, kWordGranularity);
+  selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
   selection_in_flat_tree =
       CreateVisibleSelection(SelectionInFlatTree::Builder()
                                  .Collapse(PositionInFlatTree(five, 1))
                                  .Build());
   selection_in_flat_tree =
-      ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+      ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
   EXPECT_EQ(Position(five, 1), selection.Base());
   EXPECT_EQ(Position(five, 1), selection.Extent());
@@ -232,7 +232,7 @@
           SelectionInFlatTree::Builder()
               .Collapse(PositionInFlatTree(first, 0))
               .Build(),
-          kWordGranularity);
+          TextGranularity::kWord);
   EXPECT_EQ(PositionInFlatTree(first, 0), selection.Start());
   EXPECT_EQ(PositionInFlatTree(first, 0), selection.End());
 }
@@ -419,9 +419,9 @@
   {
     SetSelection(selection, 0);
     SetSelection(selection_in_flat_tree, 0);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(0u, range->startOffset());
@@ -435,9 +435,9 @@
   {
     SetSelection(selection, 8);
     SetSelection(selection_in_flat_tree, 8);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(6u, range->startOffset());
@@ -453,9 +453,9 @@
   {
     SetSelection(selection, 5);
     SetSelection(selection_in_flat_tree, 5);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(5u, range->startOffset());
@@ -471,9 +471,9 @@
   {
     SetSelection(selection, 26);
     SetSelection(selection_in_flat_tree, 26);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(26u, range->startOffset());
@@ -487,9 +487,9 @@
   {
     SetSelection(selection, 27);
     SetSelection(selection_in_flat_tree, 27);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(27u, range->startOffset());
@@ -503,9 +503,9 @@
   {
     SetSelection(selection, 0, 1);
     SetSelection(selection_in_flat_tree, 0, 1);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(0u, range->startOffset());
@@ -519,9 +519,9 @@
   {
     SetSelection(selection, 2, 8);
     SetSelection(selection_in_flat_tree, 2, 8);
-    selection = ExpandUsingGranularity(selection, kWordGranularity);
+    selection = ExpandUsingGranularity(selection, TextGranularity::kWord);
     selection_in_flat_tree =
-        ExpandUsingGranularity(selection_in_flat_tree, kWordGranularity);
+        ExpandUsingGranularity(selection_in_flat_tree, TextGranularity::kWord);
 
     Range* range = CreateRange(FirstEphemeralRangeOf(selection));
     EXPECT_EQ(0u, range->startOffset());
diff --git a/third_party/WebKit/Source/core/editing/WebSubstringUtil.mm b/third_party/WebKit/Source/core/editing/WebSubstringUtil.mm
index 0e4116e9..ca0473f 100644
--- a/third_party/WebKit/Source/core/editing/WebSubstringUtil.mm
+++ b/third_party/WebKit/Source/core/editing/WebSubstringUtil.mm
@@ -169,7 +169,7 @@
   // Expand to word under point.
   const VisibleSelection& selection = CreateVisibleSelectionWithGranularity(
       SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(),
-      kWordGranularity);
+      TextGranularity::kWord);
   const EphemeralRange word_range = selection.ToNormalizedEphemeralRange();
 
   // Convert to NSAttributedString.
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
index 8e46daf8..80353fe 100644
--- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -272,10 +272,10 @@
   const TextIteratorBehavior behavior =
       TextIteratorBehavior::AllVisiblePositionsRangeLengthBehavior();
 
-  int start_index = TextIterator::RangeLength(
-      start_range->StartPosition(), start_range->EndPosition(), behavior);
-  int end_index = TextIterator::RangeLength(end_range->StartPosition(),
-                                            end_range->EndPosition(), behavior);
+  int start_index =
+      TextIterator::RangeLength(EphemeralRange(start_range), behavior);
+  int end_index =
+      TextIterator::RangeLength(EphemeralRange(end_range), behavior);
 
   VisiblePosition paragraph_start(StartOfParagraph(visible_start));
   VisiblePosition next_paragraph_start(
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index 2400a5f..3ee9568 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -723,7 +723,7 @@
       DCHECK(frame.GetDocument());
       TypingCommand::DeleteKeyPressed(
           *frame.GetDocument(),
-          frame.Selection().Granularity() == kWordGranularity
+          frame.Selection().Granularity() == TextGranularity::kWord
               ? TypingCommand::kSmartDelete
               : 0);
       return true;
@@ -736,8 +736,8 @@
                                   Event*,
                                   EditorCommandSource,
                                   const String&) {
-  frame.GetEditor().DeleteWithDirection(DeleteDirection::kBackward,
-                                        kCharacterGranularity, false, true);
+  frame.GetEditor().DeleteWithDirection(
+      DeleteDirection::kBackward, TextGranularity::kCharacter, false, true);
   return true;
 }
 
@@ -748,8 +748,8 @@
     const String&) {
   DLOG(ERROR) << "DeleteBackwardByDecomposingPreviousCharacter is not "
                  "implemented, doing DeleteBackward instead";
-  frame.GetEditor().DeleteWithDirection(DeleteDirection::kBackward,
-                                        kCharacterGranularity, false, true);
+  frame.GetEditor().DeleteWithDirection(
+      DeleteDirection::kBackward, TextGranularity::kCharacter, false, true);
   return true;
 }
 
@@ -757,8 +757,8 @@
                                  Event*,
                                  EditorCommandSource,
                                  const String&) {
-  frame.GetEditor().DeleteWithDirection(DeleteDirection::kForward,
-                                        kCharacterGranularity, false, true);
+  frame.GetEditor().DeleteWithDirection(
+      DeleteDirection::kForward, TextGranularity::kCharacter, false, true);
   return true;
 }
 
@@ -766,8 +766,8 @@
                                            Event*,
                                            EditorCommandSource,
                                            const String&) {
-  frame.GetEditor().DeleteWithDirection(DeleteDirection::kBackward,
-                                        kLineBoundary, true, false);
+  frame.GetEditor().DeleteWithDirection(
+      DeleteDirection::kBackward, TextGranularity::kLineBoundary, true, false);
   return true;
 }
 
@@ -776,7 +776,8 @@
                                                 EditorCommandSource,
                                                 const String&) {
   frame.GetEditor().DeleteWithDirection(DeleteDirection::kBackward,
-                                        kParagraphBoundary, true, false);
+                                        TextGranularity::kParagraphBoundary,
+                                        true, false);
   return true;
 }
 
@@ -787,8 +788,8 @@
   // Despite its name, this command should delete the newline at the end of a
   // paragraph if you are at the end of a paragraph (like
   // DeleteToEndOfParagraph).
-  frame.GetEditor().DeleteWithDirection(DeleteDirection::kForward,
-                                        kLineBoundary, true, false);
+  frame.GetEditor().DeleteWithDirection(
+      DeleteDirection::kForward, TextGranularity::kLineBoundary, true, false);
   return true;
 }
 
@@ -799,7 +800,8 @@
   // Despite its name, this command should delete the newline at the end of
   // a paragraph if you are at the end of a paragraph.
   frame.GetEditor().DeleteWithDirection(DeleteDirection::kForward,
-                                        kParagraphBoundary, true, false);
+                                        TextGranularity::kParagraphBoundary,
+                                        true, false);
   return true;
 }
 
@@ -828,7 +830,7 @@
                                       EditorCommandSource,
                                       const String&) {
   frame.GetEditor().DeleteWithDirection(DeleteDirection::kBackward,
-                                        kWordGranularity, true, false);
+                                        TextGranularity::kWord, true, false);
   return true;
 }
 
@@ -837,7 +839,7 @@
                                      EditorCommandSource,
                                      const String&) {
   frame.GetEditor().DeleteWithDirection(DeleteDirection::kForward,
-                                        kWordGranularity, true, false);
+                                        TextGranularity::kWord, true, false);
   return true;
 }
 
@@ -911,8 +913,8 @@
   EditingState editing_state;
   switch (source) {
     case kCommandFromMenuOrKeyBinding:
-      frame.GetEditor().DeleteWithDirection(DeleteDirection::kForward,
-                                            kCharacterGranularity, false, true);
+      frame.GetEditor().DeleteWithDirection(
+          DeleteDirection::kForward, TextGranularity::kCharacter, false, true);
       return true;
     case kCommandFromDOM:
       // Doesn't scroll to make the selection visible, or modify the kill ring.
@@ -1154,7 +1156,7 @@
                                 EditorCommandSource,
                                 const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kCharacterGranularity, kUserTriggered);
+                           TextGranularity::kCharacter, kUserTriggered);
   return true;
 }
 
@@ -1163,7 +1165,7 @@
                                                   EditorCommandSource,
                                                   const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kCharacterGranularity,
+                           kDirectionBackward, TextGranularity::kCharacter,
                            kUserTriggered);
   return true;
 }
@@ -1173,7 +1175,7 @@
                             EditorCommandSource,
                             const String&) {
   return frame.Selection().Modify(FrameSelection::kAlterationMove,
-                                  kDirectionForward, kLineGranularity,
+                                  kDirectionForward, TextGranularity::kLine,
                                   kUserTriggered);
 }
 
@@ -1182,7 +1184,7 @@
                                               EditorCommandSource,
                                               const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kLineGranularity, kUserTriggered);
+                           TextGranularity::kLine, kUserTriggered);
   return true;
 }
 
@@ -1191,7 +1193,7 @@
                                EditorCommandSource,
                                const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kCharacterGranularity, kUserTriggered);
+                           TextGranularity::kCharacter, kUserTriggered);
   return true;
 }
 
@@ -1200,7 +1202,7 @@
                                                  EditorCommandSource,
                                                  const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kCharacterGranularity, kUserTriggered);
+                           TextGranularity::kCharacter, kUserTriggered);
   return true;
 }
 
@@ -1209,7 +1211,7 @@
                             EditorCommandSource,
                             const String&) {
   return frame.Selection().Modify(FrameSelection::kAlterationMove,
-                                  kDirectionLeft, kCharacterGranularity,
+                                  kDirectionLeft, TextGranularity::kCharacter,
                                   kUserTriggered);
 }
 
@@ -1218,7 +1220,7 @@
                                               EditorCommandSource,
                                               const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionLeft,
-                           kCharacterGranularity, kUserTriggered);
+                           TextGranularity::kCharacter, kUserTriggered);
   return true;
 }
 
@@ -1271,7 +1273,7 @@
                              EditorCommandSource,
                              const String&) {
   return frame.Selection().Modify(FrameSelection::kAlterationMove,
-                                  kDirectionRight, kCharacterGranularity,
+                                  kDirectionRight, TextGranularity::kCharacter,
                                   kUserTriggered);
 }
 
@@ -1280,7 +1282,7 @@
                                                EditorCommandSource,
                                                const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionRight,
-                           kCharacterGranularity, kUserTriggered);
+                           TextGranularity::kCharacter, kUserTriggered);
   return true;
 }
 
@@ -1289,7 +1291,7 @@
                                              EditorCommandSource,
                                              const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kDocumentBoundary, kUserTriggered);
+                           TextGranularity::kDocumentBoundary, kUserTriggered);
   return true;
 }
 
@@ -1299,8 +1301,8 @@
     EditorCommandSource,
     const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kDocumentBoundary,
-                           kUserTriggered);
+                           kDirectionBackward,
+                           TextGranularity::kDocumentBoundary, kUserTriggered);
   return true;
 }
 
@@ -1309,7 +1311,7 @@
                                          EditorCommandSource,
                                          const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1318,7 +1320,8 @@
                                                            EditorCommandSource,
                                                            const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kLineBoundary, kUserTriggered);
+                           kDirectionBackward, TextGranularity::kLineBoundary,
+                           kUserTriggered);
   return true;
 }
 
@@ -1327,7 +1330,7 @@
                                               EditorCommandSource,
                                               const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kParagraphBoundary, kUserTriggered);
+                           TextGranularity::kParagraphBoundary, kUserTriggered);
   return true;
 }
 
@@ -1337,8 +1340,8 @@
     EditorCommandSource,
     const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kParagraphBoundary,
-                           kUserTriggered);
+                           kDirectionBackward,
+                           TextGranularity::kParagraphBoundary, kUserTriggered);
   return true;
 }
 
@@ -1347,7 +1350,7 @@
                                              EditorCommandSource,
                                              const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kSentenceBoundary, kUserTriggered);
+                           TextGranularity::kSentenceBoundary, kUserTriggered);
   return true;
 }
 
@@ -1357,8 +1360,8 @@
     EditorCommandSource,
     const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kSentenceBoundary,
-                           kUserTriggered);
+                           kDirectionBackward,
+                           TextGranularity::kSentenceBoundary, kUserTriggered);
   return true;
 }
 
@@ -1367,7 +1370,7 @@
                                        EditorCommandSource,
                                        const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kDocumentBoundary, kUserTriggered);
+                           TextGranularity::kDocumentBoundary, kUserTriggered);
   return true;
 }
 
@@ -1376,7 +1379,7 @@
                                                          EditorCommandSource,
                                                          const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kDocumentBoundary, kUserTriggered);
+                           TextGranularity::kDocumentBoundary, kUserTriggered);
   return true;
 }
 
@@ -1385,7 +1388,7 @@
                                        EditorCommandSource,
                                        const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kSentenceBoundary, kUserTriggered);
+                           TextGranularity::kSentenceBoundary, kUserTriggered);
   return true;
 }
 
@@ -1394,7 +1397,7 @@
                                                          EditorCommandSource,
                                                          const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kSentenceBoundary, kUserTriggered);
+                           TextGranularity::kSentenceBoundary, kUserTriggered);
   return true;
 }
 
@@ -1403,7 +1406,7 @@
                                    EditorCommandSource,
                                    const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1412,7 +1415,7 @@
                                                      EditorCommandSource,
                                                      const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1421,7 +1424,7 @@
                                         EditorCommandSource,
                                         const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kParagraphBoundary, kUserTriggered);
+                           TextGranularity::kParagraphBoundary, kUserTriggered);
   return true;
 }
 
@@ -1430,7 +1433,7 @@
                                                           EditorCommandSource,
                                                           const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kParagraphBoundary, kUserTriggered);
+                           TextGranularity::kParagraphBoundary, kUserTriggered);
   return true;
 }
 
@@ -1439,7 +1442,7 @@
                                          EditorCommandSource,
                                          const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kParagraphGranularity, kUserTriggered);
+                           TextGranularity::kParagraph, kUserTriggered);
   return true;
 }
 
@@ -1448,7 +1451,7 @@
                                                            EditorCommandSource,
                                                            const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kParagraphGranularity,
+                           kDirectionBackward, TextGranularity::kParagraph,
                            kUserTriggered);
   return true;
 }
@@ -1458,7 +1461,7 @@
                                         EditorCommandSource,
                                         const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kParagraphGranularity, kUserTriggered);
+                           TextGranularity::kParagraph, kUserTriggered);
   return true;
 }
 
@@ -1467,7 +1470,7 @@
                                                           EditorCommandSource,
                                                           const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kParagraphGranularity, kUserTriggered);
+                           TextGranularity::kParagraph, kUserTriggered);
   return true;
 }
 
@@ -1476,7 +1479,7 @@
                           EditorCommandSource,
                           const String&) {
   return frame.Selection().Modify(FrameSelection::kAlterationMove,
-                                  kDirectionBackward, kLineGranularity,
+                                  kDirectionBackward, TextGranularity::kLine,
                                   kUserTriggered);
 }
 
@@ -1485,7 +1488,7 @@
                                             EditorCommandSource,
                                             const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kLineGranularity,
+                           kDirectionBackward, TextGranularity::kLine,
                            kUserTriggered);
   return true;
 }
@@ -1495,7 +1498,7 @@
                                     EditorCommandSource,
                                     const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionBackward,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1504,7 +1507,7 @@
                                                       EditorCommandSource,
                                                       const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend,
-                           kDirectionBackward, kWordGranularity,
+                           kDirectionBackward, TextGranularity::kWord,
                            kUserTriggered);
   return true;
 }
@@ -1514,7 +1517,7 @@
                                    EditorCommandSource,
                                    const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionForward,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1523,7 +1526,7 @@
                                                      EditorCommandSource,
                                                      const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1532,7 +1535,7 @@
                                 EditorCommandSource,
                                 const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionLeft,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1541,7 +1544,7 @@
                                                   EditorCommandSource,
                                                   const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionLeft,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1550,7 +1553,7 @@
                                  EditorCommandSource,
                                  const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionRight,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1559,7 +1562,7 @@
                                                    EditorCommandSource,
                                                    const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionRight,
-                           kWordGranularity, kUserTriggered);
+                           TextGranularity::kWord, kUserTriggered);
   return true;
 }
 
@@ -1568,7 +1571,7 @@
                                        EditorCommandSource,
                                        const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionLeft,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1577,7 +1580,7 @@
                                                          EditorCommandSource,
                                                          const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionLeft,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1586,7 +1589,7 @@
                                         EditorCommandSource,
                                         const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationMove, kDirectionRight,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1595,7 +1598,7 @@
                                                           EditorCommandSource,
                                                           const String&) {
   frame.Selection().Modify(FrameSelection::kAlterationExtend, kDirectionRight,
-                           kLineBoundary, kUserTriggered);
+                           TextGranularity::kLineBoundary, kUserTriggered);
   return true;
 }
 
@@ -1761,21 +1764,21 @@
                               Event*,
                               EditorCommandSource,
                               const String&) {
-  return ExpandSelectionToGranularity(frame, kLineGranularity);
+  return ExpandSelectionToGranularity(frame, TextGranularity::kLine);
 }
 
 static bool ExecuteSelectParagraph(LocalFrame& frame,
                                    Event*,
                                    EditorCommandSource,
                                    const String&) {
-  return ExpandSelectionToGranularity(frame, kParagraphGranularity);
+  return ExpandSelectionToGranularity(frame, TextGranularity::kParagraph);
 }
 
 static bool ExecuteSelectSentence(LocalFrame& frame,
                                   Event*,
                                   EditorCommandSource,
                                   const String&) {
-  return ExpandSelectionToGranularity(frame, kSentenceGranularity);
+  return ExpandSelectionToGranularity(frame, TextGranularity::kSentence);
 }
 
 static bool ExecuteSelectToMark(LocalFrame& frame,
@@ -1799,7 +1802,7 @@
                               Event*,
                               EditorCommandSource,
                               const String&) {
-  return ExpandSelectionToGranularity(frame, kWordGranularity);
+  return ExpandSelectionToGranularity(frame, TextGranularity::kWord);
 }
 
 static bool ExecuteSetMark(LocalFrame& frame,
@@ -2857,10 +2860,12 @@
   // support.
   DCHECK(GetFrame().GetDocument()->IsActive());
   if (command_name == "DeleteToEndOfParagraph") {
-    if (!DeleteWithDirection(DeleteDirection::kForward, kParagraphBoundary,
-                             true, false))
-      DeleteWithDirection(DeleteDirection::kForward, kCharacterGranularity,
-                          true, false);
+    if (!DeleteWithDirection(DeleteDirection::kForward,
+                             TextGranularity::kParagraphBoundary, true,
+                             false)) {
+      DeleteWithDirection(DeleteDirection::kForward,
+                          TextGranularity::kCharacter, true, false);
+    }
     return true;
   }
   if (command_name == "DeleteBackward")
@@ -3013,28 +3018,28 @@
     case WebEditingCommandType::kDelete:
     case WebEditingCommandType::kDeleteBackward:
       return RangesFromCurrentSelectionOrExtendCaret(
-          *frame_, kDirectionBackward, kCharacterGranularity);
+          *frame_, kDirectionBackward, TextGranularity::kCharacter);
     case WebEditingCommandType::kDeleteForward:
-      return RangesFromCurrentSelectionOrExtendCaret(*frame_, kDirectionForward,
-                                                     kCharacterGranularity);
+      return RangesFromCurrentSelectionOrExtendCaret(
+          *frame_, kDirectionForward, TextGranularity::kCharacter);
     case WebEditingCommandType::kDeleteToBeginningOfLine:
       return RangesFromCurrentSelectionOrExtendCaret(
-          *frame_, kDirectionBackward, kLineGranularity);
+          *frame_, kDirectionBackward, TextGranularity::kLine);
     case WebEditingCommandType::kDeleteToBeginningOfParagraph:
       return RangesFromCurrentSelectionOrExtendCaret(
-          *frame_, kDirectionBackward, kParagraphGranularity);
+          *frame_, kDirectionBackward, TextGranularity::kParagraph);
     case WebEditingCommandType::kDeleteToEndOfLine:
       return RangesFromCurrentSelectionOrExtendCaret(*frame_, kDirectionForward,
-                                                     kLineGranularity);
+                                                     TextGranularity::kLine);
     case WebEditingCommandType::kDeleteToEndOfParagraph:
-      return RangesFromCurrentSelectionOrExtendCaret(*frame_, kDirectionForward,
-                                                     kParagraphGranularity);
+      return RangesFromCurrentSelectionOrExtendCaret(
+          *frame_, kDirectionForward, TextGranularity::kParagraph);
     case WebEditingCommandType::kDeleteWordBackward:
       return RangesFromCurrentSelectionOrExtendCaret(
-          *frame_, kDirectionBackward, kWordGranularity);
+          *frame_, kDirectionBackward, TextGranularity::kWord);
     case WebEditingCommandType::kDeleteWordForward:
       return RangesFromCurrentSelectionOrExtendCaret(*frame_, kDirectionForward,
-                                                     kWordGranularity);
+                                                     TextGranularity::kWord);
     default:
       return TargetRangesForInputEvent(*target);
   }
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index b1eb43c4..5cad4703 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -194,7 +194,7 @@
 void TypingCommand::DeleteKeyPressed(Document& document,
                                      Options options,
                                      TextGranularity granularity) {
-  if (granularity == kCharacterGranularity) {
+  if (granularity == TextGranularity::kCharacter) {
     LocalFrame* frame = document.GetFrame();
     if (TypingCommand* last_typing_command =
             LastTypingCommandIfStillOpenForTyping(frame)) {
@@ -224,7 +224,7 @@
                                             TextGranularity granularity) {
   // FIXME: Forward delete in TextEdit appears to open and close a new typing
   // command.
-  if (granularity == kCharacterGranularity) {
+  if (granularity == TextGranularity::kCharacter) {
     LocalFrame* frame = document.GetFrame();
     if (TypingCommand* last_typing_command =
             LastTypingCommandIfStillOpenForTyping(frame)) {
@@ -727,9 +727,11 @@
       selection_modifier.Modify(FrameSelection::kAlterationExtend,
                                 kDirectionBackward, granularity);
       if (kill_ring && selection_modifier.Selection().IsCaret() &&
-          granularity != kCharacterGranularity)
+          granularity != TextGranularity::kCharacter) {
         selection_modifier.Modify(FrameSelection::kAlterationExtend,
-                                  kDirectionBackward, kCharacterGranularity);
+                                  kDirectionBackward,
+                                  TextGranularity::kCharacter);
+      }
 
       const VisiblePosition& visible_start(EndingSelection().VisibleStart());
       const VisiblePosition& previous_position =
@@ -801,7 +803,7 @@
 
       selection_to_delete = selection_modifier.Selection();
 
-      if (granularity == kCharacterGranularity &&
+      if (granularity == TextGranularity::kCharacter &&
           selection_to_delete.End().ComputeContainerNode() ==
               selection_to_delete.Start().ComputeContainerNode() &&
           selection_to_delete.End().ComputeOffsetInContainerNode() -
@@ -890,9 +892,11 @@
       selection_modifier.Modify(FrameSelection::kAlterationExtend,
                                 kDirectionForward, granularity);
       if (kill_ring && selection_modifier.Selection().IsCaret() &&
-          granularity != kCharacterGranularity)
+          granularity != TextGranularity::kCharacter) {
         selection_modifier.Modify(FrameSelection::kAlterationExtend,
-                                  kDirectionForward, kCharacterGranularity);
+                                  kDirectionForward,
+                                  TextGranularity::kCharacter);
+      }
 
       Position downstream_end =
           MostForwardCaretPosition(EndingSelection().End());
@@ -926,11 +930,13 @@
 
       // deleting to end of paragraph when at end of paragraph needs to merge
       // the next paragraph (if any)
-      if (granularity == kParagraphBoundary &&
+      if (granularity == TextGranularity::kParagraphBoundary &&
           selection_modifier.Selection().IsCaret() &&
-          IsEndOfParagraph(selection_modifier.Selection().VisibleEnd()))
+          IsEndOfParagraph(selection_modifier.Selection().VisibleEnd())) {
         selection_modifier.Modify(FrameSelection::kAlterationExtend,
-                                  kDirectionForward, kCharacterGranularity);
+                                  kDirectionForward,
+                                  TextGranularity::kCharacter);
+      }
 
       selection_to_delete = selection_modifier.Selection();
       if (!StartingSelection().IsRange() ||
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index a5aba47..dec97a8 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -61,11 +61,12 @@
   static void DeleteSelection(Document&, Options = 0);
   static void DeleteKeyPressed(Document&,
                                Options,
-                               TextGranularity = kCharacterGranularity);
-  static void ForwardDeleteKeyPressed(Document&,
-                                      EditingState*,
-                                      Options = 0,
-                                      TextGranularity = kCharacterGranularity);
+                               TextGranularity = TextGranularity::kCharacter);
+  static void ForwardDeleteKeyPressed(
+      Document&,
+      EditingState*,
+      Options = 0,
+      TextGranularity = TextGranularity::kCharacter);
   static void InsertText(Document&,
                          const String&,
                          Options,
@@ -114,7 +115,7 @@
       ETypingCommand command,
       const String& text = "",
       Options options = 0,
-      TextGranularity granularity = kCharacterGranularity) {
+      TextGranularity granularity = TextGranularity::kCharacter) {
     return new TypingCommand(document, command, text, options, granularity,
                              kTextCompositionNone);
   }
@@ -125,7 +126,7 @@
                                Options options,
                                TextCompositionType composition_type) {
     return new TypingCommand(document, command, text, options,
-                             kCharacterGranularity, composition_type);
+                             TextGranularity::kCharacter, composition_type);
   }
 
   TypingCommand(Document&,
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index aaed16df..58efa09 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -937,6 +937,13 @@
 }
 
 template <typename Strategy>
+int TextIteratorAlgorithm<Strategy>::RangeLength(
+    const EphemeralRangeTemplate<Strategy>& range,
+    const TextIteratorBehavior& behavior) {
+  return RangeLength(range.StartPosition(), range.EndPosition(), behavior);
+}
+
+template <typename Strategy>
 bool TextIteratorAlgorithm<Strategy>::IsInTextSecurityMode() const {
   return IsTextSecurityNode(GetNode());
 }
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index 6a1037e5..2095016 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -106,12 +106,18 @@
   // Computes the length of the given range using a text iterator according to
   // the specified iteration behavior. The default iteration behavior is to
   // always emit object replacement characters for replaced elements.
+  // TODO(editing-dev): We should remove start/end version of |RangeLength()|.
   static int RangeLength(
       const PositionTemplate<Strategy>& start,
       const PositionTemplate<Strategy>& end,
       const TextIteratorBehavior& =
           TextIteratorBehavior::DefaultRangeLengthBehavior());
 
+  static int RangeLength(
+      const EphemeralRangeTemplate<Strategy>&,
+      const TextIteratorBehavior& =
+          TextIteratorBehavior::DefaultRangeLengthBehavior());
+
   static bool ShouldEmitTabBeforeNode(Node*);
   static bool ShouldEmitNewlineBeforeNode(Node&);
   static bool ShouldEmitNewlineAfterNode(Node&);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
index 93eae7b8..6b44583 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTest.cpp
@@ -453,10 +453,9 @@
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   Node* div_node = GetDocument().getElementById("div");
-  Range* range = Range::Create(GetDocument(), div_node, 0, div_node, 3);
+  const EphemeralRange range(Position(div_node, 0), Position(div_node, 3));
 
-  EXPECT_EQ(3, TextIterator::RangeLength(range->StartPosition(),
-                                         range->EndPosition()));
+  EXPECT_EQ(3, TextIterator::RangeLength(range));
 }
 
 TEST_F(TextIteratorTest, RangeLengthInMultilineSpan) {
@@ -478,12 +477,12 @@
   Node* text_node = span_node->firstChild();
 
   // Select the word "two", this is the last word on the line.
-  const Position start = Position(text_node, 4);
-  const Position end = Position(text_node, 7);
 
-  EXPECT_EQ(4, TextIterator::RangeLength(start, end));
+  const EphemeralRange range(Position(text_node, 4), Position(text_node, 7));
+
+  EXPECT_EQ(4, TextIterator::RangeLength(range));
   EXPECT_EQ(3, TextIterator::RangeLength(
-                   start, end,
+                   range,
                    TextIteratorBehavior::NoTrailingSpaceRangeLengthBehavior()));
 }
 
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/ColdModeSpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/ColdModeSpellCheckRequester.cpp
index 4f813392..0163414 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/ColdModeSpellCheckRequester.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/ColdModeSpellCheckRequester.cpp
@@ -130,8 +130,7 @@
 void ColdModeSpellCheckRequester::InitializeForCurrentRootEditable() {
   const EphemeralRange& full_range =
       EphemeralRange::RangeOfContents(*current_root_editable_);
-  current_full_length_ = TextIterator::RangeLength(full_range.StartPosition(),
-                                                   full_range.EndPosition());
+  current_full_length_ = TextIterator::RangeLength(full_range);
 
   current_chunk_index_ = 0;
   current_chunk_start_ = full_range.StartPosition();
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
index 801413f..b9089f3a 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/HotModeSpellCheckRequester.cpp
@@ -68,8 +68,7 @@
                                              const Position& position) {
   // Check everything in |editable| if its total length is short.
   const EphemeralRange& full_range = EphemeralRange::RangeOfContents(editable);
-  const int full_length = TextIterator::RangeLength(full_range.StartPosition(),
-                                                    full_range.EndPosition());
+  const int full_length = TextIterator::RangeLength(full_range);
   // TODO(xiaochengh): There is no need to check if |full_length <= 2|, since
   // we don't consider two characters as misspelled. However, a lot of layout
   // tests depend on "zz" as misspelled, which should be changed.
@@ -79,8 +78,7 @@
   // Otherwise, if |position| is in a short paragraph, check the paragraph.
   const EphemeralRange& paragraph_range =
       ExpandToParagraphBoundary(EphemeralRange(position));
-  const int paragraph_length = TextIterator::RangeLength(
-      paragraph_range.StartPosition(), paragraph_range.EndPosition());
+  const int paragraph_length = TextIterator::RangeLength(paragraph_range);
   if (paragraph_length <= kHotModeChunkSize)
     return paragraph_range;
 
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp
index b9aeb06c..96b2c71 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingParagraph.cpp
@@ -77,8 +77,7 @@
 
 int TextCheckingParagraph::RangeLength() const {
   DCHECK(checking_range_.IsNotNull());
-  return TextIterator::RangeLength(ParagraphRange().StartPosition(),
-                                   ParagraphRange().EndPosition());
+  return TextIterator::RangeLength(ParagraphRange());
 }
 
 EphemeralRange TextCheckingParagraph::ParagraphRange() const {
@@ -130,17 +129,16 @@
 int TextCheckingParagraph::CheckingStart() const {
   DCHECK(checking_range_.IsNotNull());
   if (checking_start_ == -1)
-    checking_start_ = TextIterator::RangeLength(OffsetAsRange().StartPosition(),
-                                                OffsetAsRange().EndPosition());
+    checking_start_ = TextIterator::RangeLength(OffsetAsRange());
   return checking_start_;
 }
 
 int TextCheckingParagraph::CheckingEnd() const {
   DCHECK(checking_range_.IsNotNull());
-  if (checking_end_ == -1)
-    checking_end_ = CheckingStart() +
-                    TextIterator::RangeLength(CheckingRange().StartPosition(),
-                                              CheckingRange().EndPosition());
+  if (checking_end_ == -1) {
+    checking_end_ =
+        CheckingStart() + TextIterator::RangeLength(CheckingRange());
+  }
   return checking_end_;
 }
 
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..f2f05cca 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -11,6 +11,7 @@
 #include "core/inspector/ConsoleMessage.h"
 #include "core/page/Page.h"
 #include "core/workers/WorkerOrWorkletGlobalScope.h"
+#include "public/platform/WebFeaturePolicyFeature.h"
 
 namespace {
 
@@ -70,6 +71,18 @@
       feature, milestoneString(milestone), replacement, details);
 }
 
+String DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+    const char* function,
+    const char* allow_string,
+    Milestone milestone) {
+  return String::Format(
+      "%s usage in cross-origin iframes is deprecated and will be disabled in "
+      "%s. To continue to use this feature, it must be enabled by the "
+      "embedding document using Feature Policy, e.g. "
+      "<iframe allow=\"%s\" ...>. See https://goo.gl/EuHzyv for more details.",
+      function, milestoneString(milestone), allow_string);
+}
+
 }  // anonymous namespace
 
 namespace blink {
@@ -180,6 +193,58 @@
   CountDeprecationCrossOriginIframe(frame, feature);
 }
 
+void Deprecation::CountDeprecationFeaturePolicy(
+    const Document& document,
+    WebFeaturePolicyFeature feature) {
+  LocalFrame* frame = document.GetFrame();
+  if (!frame)
+    return;
+
+  // If the feature is allowed, don't log a warning.
+  if (frame->IsFeatureEnabled(feature))
+    return;
+
+  // If the feature is disabled, log a warning but only if the request is from a
+  // cross-origin iframe. Ideally we would check here if the feature is actually
+  // disabled due to the parent frame's policy (as opposed to the current frame
+  // disabling the feature on itself) but that can't happen right now anyway
+  // (until the general syntax is shipped) and this is also a good enough
+  // approximation for deprecation messages.
+  switch (feature) {
+    case WebFeaturePolicyFeature::kEme:
+      CountDeprecationCrossOriginIframe(
+          frame,
+          WebFeature::
+              kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe);
+      break;
+    case WebFeaturePolicyFeature::kGeolocation:
+      CountDeprecationCrossOriginIframe(
+          frame,
+          WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe);
+      break;
+    case WebFeaturePolicyFeature::kMicrophone:
+      CountDeprecationCrossOriginIframe(
+          frame,
+          WebFeature::
+              kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe);
+      break;
+    case WebFeaturePolicyFeature::kCamera:
+      CountDeprecationCrossOriginIframe(
+          frame,
+          WebFeature::
+              kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe);
+      break;
+    case WebFeaturePolicyFeature::kMidiFeature:
+      CountDeprecationCrossOriginIframe(
+          frame,
+          WebFeature::
+              kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
 String Deprecation::DeprecationMessage(WebFeature feature) {
   switch (feature) {
     // Quota
@@ -252,7 +317,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.");
 
@@ -449,6 +514,25 @@
           "is deprecated, and is planned to be removed in %s. Please refer to "
           "https://goo.gl/EGXzpw for possible migration paths.",
           milestoneString(M65));
+    case WebFeature::
+        kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe:
+      return DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+          "requestMediaKeySystemAccess", "encrypted-media", M63);
+    case WebFeature::kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe:
+      return DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+          "getCurrentPosition and watchPosition", "geolocation", M63);
+    case WebFeature::
+        kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe:
+      return DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+          "getUserMedia (microphone)", "microphone", M63);
+    case WebFeature::
+        kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe:
+      return DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+          "getUserMedia (camera)", "camera", M63);
+    case WebFeature::
+        kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe:
+      return DeprecatedWillBeDisabledByFeaturePolicyInCrossOriginIframe(
+          "requestMIDIAccess", "midi", M63);
 
     // Features that aren't deprecated don't have a deprecation message.
     default:
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.h b/third_party/WebKit/Source/core/frame/Deprecation.h
index 99fe14d..361c8da 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.h
+++ b/third_party/WebKit/Source/core/frame/Deprecation.h
@@ -14,6 +14,7 @@
 namespace blink {
 
 class LocalFrame;
+enum class WebFeaturePolicyFeature;
 
 class CORE_EXPORT Deprecation {
   DISALLOW_NEW();
@@ -47,6 +48,9 @@
   // have script access into the top level document.
   static void CountDeprecationCrossOriginIframe(const LocalFrame*, WebFeature);
   static void CountDeprecationCrossOriginIframe(const Document&, WebFeature);
+
+  static void CountDeprecationFeaturePolicy(const Document&,
+                                            WebFeaturePolicyFeature);
   static String DeprecationMessage(WebFeature);
 
   // Note: this is only public for tests.
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/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp
index 30ebcc03..140f701 100644
--- a/third_party/WebKit/Source/core/frame/History.cpp
+++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -116,6 +116,28 @@
                       : kScrollRestorationAuto;
 }
 
+// TODO(crbug.com/394296): This is not the long-term fix to IPC flooding that we
+// need. However, it does somewhat mitigate the immediate concern of |pushState|
+// and |replaceState| DoS (assuming the renderer has not been compromised).
+bool History::ShouldThrottleStateObjectChanges() {
+  const int kStateUpdateLimit = 50;
+
+  if (state_flood_guard.count > kStateUpdateLimit) {
+    static constexpr auto kStateUpdateLimitResetInterval =
+        TimeDelta::FromSeconds(10);
+    const auto now = TimeTicks::Now();
+    if (now - state_flood_guard.last_updated > kStateUpdateLimitResetInterval) {
+      state_flood_guard.count = 0;
+      state_flood_guard.last_updated = now;
+      return false;
+    }
+    return true;
+  }
+
+  state_flood_guard.count++;
+  return false;
+}
+
 bool History::stateChanged() const {
   return last_state_object_requested_ != StateInternal();
 }
@@ -230,6 +252,9 @@
     return;
   }
 
+  if (ShouldThrottleStateObjectChanges())
+    return;
+
   GetFrame()->Loader().UpdateForSameDocumentNavigation(
       full_url, kSameDocumentNavigationHistoryApi, std::move(data),
       restoration_type, type, GetFrame()->GetDocument());
diff --git a/third_party/WebKit/Source/core/frame/History.h b/third_party/WebKit/Source/core/frame/History.h
index fb7fc5e..9c2f875 100644
--- a/third_party/WebKit/Source/core/frame/History.h
+++ b/third_party/WebKit/Source/core/frame/History.h
@@ -33,6 +33,7 @@
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
+#include "platform/wtf/Time.h"
 
 namespace blink {
 
@@ -102,7 +103,13 @@
   SerializedScriptValue* StateInternal() const;
   HistoryScrollRestorationType ScrollRestorationInternal() const;
 
+  bool ShouldThrottleStateObjectChanges();
+
   RefPtr<SerializedScriptValue> last_state_object_requested_;
+  struct {
+    int count;
+    TimeTicks last_updated;
+  } state_flood_guard;
 };
 
 }  // namespace blink
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..d45d2593 100644
--- a/third_party/WebKit/Source/core/frame/Window.idl
+++ b/third_party/WebKit/Source/core/frame/Window.idl
@@ -89,7 +89,7 @@
     [Measure] long requestIdleCallback(IdleRequestCallback callback, optional IdleRequestOptions options);
     void cancelIdleCallback(long handle);
 
-    [CrossOrigin, Custom, RaisesException] void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
+    [CrossOrigin, Custom, RaisesException] void postMessage(any message, DOMString targetOrigin, optional sequence<object> transfer = []);
 
     // Custom elements
     // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-api
@@ -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;
@@ -206,21 +205,6 @@
     attribute DOMMatrixConstructor WebKitCSSMatrix;
 };
 
-// https://html.spec.whatwg.org/#transferable-objects
-//
-// Expressing the Transferable typedef in IDL depends on https://crbug.com/240176.
-// The postMessage() methods taking a Transferable array argument have custom
-// binding code that is able to handle the Transferables that we currently
-// recognize. To be able to declare a postMessage() signature that matches
-// the implementation, we provide a Transferable typedef but with an
-// incomplete type.
-//
-// FIXME: make this typedef accurate once enough of https://crbug.com/240176
-// is in place.
-// FIXME: consider putting this typedef in an .idl file containing spec-wide
-// utility type definitions.
-typedef MessagePort Transferable;
-
 Window implements GlobalEventHandlers;
 Window implements WindowBase64;
 Window implements WindowEventHandlers;
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/DOMMatrix.cpp b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
index 90c26cd..77584f8 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.cpp
@@ -277,6 +277,11 @@
   return this;
 }
 
+DOMMatrix* DOMMatrix::perspectiveSelf(double p) {
+  matrix_->ApplyPerspective(p);
+  return this;
+}
+
 DOMMatrix* DOMMatrix::invertSelf() {
   if (matrix_->IsInvertible()) {
     matrix_ = TransformationMatrix::Create(matrix_->Inverse());
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.h b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
index fdc2432b..0bff8c0 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
@@ -112,6 +112,7 @@
                                  double angle = 0);
   DOMMatrix* skewXSelf(double sx = 0);
   DOMMatrix* skewYSelf(double sy = 0);
+  DOMMatrix* perspectiveSelf(double p);
   DOMMatrix* invertSelf();
 
   DOMMatrix* setMatrixValue(const String&, ExceptionState&);
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/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn
index 97ea827..1939452b 100644
--- a/third_party/WebKit/Source/core/html/BUILD.gn
+++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -619,16 +619,7 @@
     "track/vtt/VTTTokenizer.h",
   ]
 
-  jumbo_excluded_sources = [
-    "canvas/CanvasRenderingContext.cpp",  # https://crbug.com/716395
-
-    # Does ugly things with undef (patch incoming)
-    "parser/HTMLTokenizer.cpp",
-
-    # kSupportedTokens in both HTMLMediaElementControlsList.cpp
-    # and HTMLIFrameElementSandbox.cpp
-    "HTMLIFrameElementSandbox.cpp",
-  ]
+  jumbo_excluded_sources = [ "canvas/CanvasRenderingContext.cpp" ]  # https://crbug.com/716395
 
   configs += [
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
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/HTMLIFrameElementSandbox.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementSandbox.cpp
index 3885b445..da28648 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementSandbox.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementSandbox.cpp
@@ -10,17 +10,17 @@
 
 namespace {
 
-const char* const kSupportedTokens[] = {"allow-forms",
-                                        "allow-modals",
-                                        "allow-pointer-lock",
-                                        "allow-popups",
-                                        "allow-popups-to-escape-sandbox",
-                                        "allow-same-origin",
-                                        "allow-scripts",
-                                        "allow-top-navigation"};
+const char* const kSupportedSandboxTokens[] = {"allow-forms",
+                                               "allow-modals",
+                                               "allow-pointer-lock",
+                                               "allow-popups",
+                                               "allow-popups-to-escape-sandbox",
+                                               "allow-same-origin",
+                                               "allow-scripts",
+                                               "allow-top-navigation"};
 
 bool IsTokenSupported(const AtomicString& token) {
-  for (const char* supported_token : kSupportedTokens) {
+  for (const char* supported_token : kSupportedSandboxTokens) {
     if (token == supported_token)
       return true;
   }
diff --git a/third_party/WebKit/Source/core/html/TextControlElement.cpp b/third_party/WebKit/Source/core/html/TextControlElement.cpp
index 12bb8af..c66669e0d 100644
--- a/third_party/WebKit/Source/core/html/TextControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/TextControlElement.cpp
@@ -503,7 +503,7 @@
         GetDocument().Lifecycle());
     const SelectionInDOMTree& selection =
         frame->Selection().GetSelectionInDOMTree();
-    if (frame->Selection().Granularity() == kCharacterGranularity) {
+    if (frame->Selection().Granularity() == TextGranularity::kCharacter) {
       return IndexForPosition(InnerEditorElement(),
                               selection.ComputeStartPosition());
     }
@@ -534,7 +534,7 @@
         GetDocument().Lifecycle());
     const SelectionInDOMTree& selection =
         frame->Selection().GetSelectionInDOMTree();
-    if (frame->Selection().Granularity() == kCharacterGranularity) {
+    if (frame->Selection().Granularity() == TextGranularity::kCharacter) {
       return IndexForPosition(InnerEditorElement(),
                               selection.ComputeEndPosition());
     }
diff --git a/third_party/WebKit/Source/core/html/forms/resources/input_alert.svg b/third_party/WebKit/Source/core/html/forms/resources/input_alert.svg
index b107f94..d0aef2b 100644
--- a/third_party/WebKit/Source/core/html/forms/resources/input_alert.svg
+++ b/third_party/WebKit/Source/core/html/forms/resources/input_alert.svg
@@ -4,7 +4,19 @@
      found in the LICENSE file. -->
 <svg xmlns="http://www.w3.org/2000/svg" width="23" height="23" viewBox="0 0 47 47" id="icon">
 <rect x="0" y="0" width="47" height="47" rx="4" ry="4" fill="#ffa300"/>
+
+<rect x="19" y="10" width="9" height="15" fill="#ffbc4f" />
 <rect x="20" y="10" width="7" height="15" fill="#ffffff" />
+<rect x="20" y="9" width="7" height="1" fill="#ffb53d" />
+<rect x="20" y="25" width="7" height="1" fill="#ffd6af" />
+<rect x="20" y="26" width="7" height="1" fill="#ff7e00" />
+
+<defs>
+<linearGradient id="g1" x1="0" y1="0" x2="0" y2="1">
+<stop offset="0%" stop-color="#ffb53d" />
+<stop offset="100%" stop-color="#ff7e00" />
+</linearGradient>
+</defs>
+<circle cx="23.5" cy="33" r="4.5" fill="url(#g1)"/>
 <circle cx="23.5" cy="33" r="3.5" fill="#ffffff"/>
-<!-- TODO(tkent): Add some shadow. -->
 </svg>
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/parser/HTMLTokenizer.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
index 93b3e81..99fcb36 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
@@ -36,10 +36,6 @@
 #include "platform/wtf/ASCIICType.h"
 #include "platform/wtf/text/Unicode.h"
 
-// Please don't use DEFINE_STATIC_LOCAL in this file. The HTMLTokenizer is used
-// from multiple threads and DEFINE_STATIC_LOCAL isn't threadsafe.
-#undef DEFINE_STATIC_LOCAL
-
 namespace blink {
 
 using namespace HTMLNames;
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/ImageQualityControllerTest.cpp b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
index bed3995b2..2e545289 100644
--- a/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
@@ -60,7 +60,7 @@
                 LayoutSize(), FrameTime(obj)));
 }
 
-#if !USE(LOW_QUALITY_IMAGE_INTERPOLATION)
+#if !defined(WTF_USE_LOW_QUALITY_IMAGE_INTERPOLATION)
 
 class TestImageAnimated : public Image {
  public:
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/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index 8436b88..f760d79 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -252,8 +252,10 @@
   // min-content contribution.
   // https://drafts.csswg.org/css-align-3/#baseline-align-content
   // https://drafts.csswg.org/css-align-3/#baseline-align-self
-  bool baseline_affect_intrinsic_width = BaselineMayAffectIntrinsicWidth();
-  bool baseline_affect_intrinsic_height = BaselineMayAffectIntrinsicHeight();
+  bool baseline_affect_intrinsic_width =
+      BaselineMayAffectIntrinsicSize(kForColumns);
+  bool baseline_affect_intrinsic_height =
+      BaselineMayAffectIntrinsicSize(kForRows);
 
   // In orthogonal flow cases column track's size is determined by using the
   // computed row track's size, which it was estimated during the first cycle of
@@ -282,7 +284,8 @@
   ComputeTrackSizesForDefiniteSize(kForColumns, available_space_for_columns);
   ComputeTrackSizesForDefiniteSize(kForRows, available_space_for_rows);
 
-  if (baseline_affect_intrinsic_height) {
+  if (baseline_affect_intrinsic_height &&
+      StyleRef().LogicalHeight().IsIntrinsicOrAuto()) {
     SetLogicalHeight(ComputeTrackBasedLogicalHeight() +
                      BorderAndPaddingLogicalHeight() +
                      ScrollbarLogicalHeight());
@@ -1872,29 +1875,29 @@
              : !col_axis_alignment_context_.IsEmpty();
 }
 
-bool LayoutGrid::BaselineMayAffectIntrinsicWidth() const {
-  if (!StyleRef().LogicalWidth().IsIntrinsicOrAuto())
-    return false;
-  for (const auto& context : col_axis_alignment_context_) {
+bool LayoutGrid::BaselineMayAffectIntrinsicSize(
+    GridTrackSizingDirection direction) const {
+  const auto& contexts_map = direction == kForColumns
+                                 ? col_axis_alignment_context_
+                                 : row_axis_alignment_context_;
+  for (const auto& context : contexts_map) {
+    auto track_size =
+        track_sizing_algorithm_.GetGridTrackSize(direction, context.key);
+    // TODO(lajava): Should we consider flexible tracks as well ?
+    if (!track_size.IsContentSized())
+      continue;
     for (const auto& group : context.value->SharedGroups()) {
-      if (group.size() > 1)
-        return true;
+      if (group.size() > 1) {
+        auto grid_area_size =
+            track_sizing_algorithm_.Tracks(direction)[context.key].BaseSize();
+        if (group.MaxAscent() + group.MaxDescent() > grid_area_size)
+          return true;
+      }
     }
   }
   return false;
 }
 
-bool LayoutGrid::BaselineMayAffectIntrinsicHeight() const {
-  if (!StyleRef().LogicalHeight().IsIntrinsicOrAuto())
-    return false;
-  for (const auto& context : row_axis_alignment_context_) {
-    for (const auto& group : context.value->SharedGroups()) {
-      if (group.size() > 1)
-        return true;
-    }
-  }
-  return false;
-}
 
 void LayoutGrid::ComputeBaselineAlignmentContext() {
   for (auto* child = FirstInFlowChildBox(); child;
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h
index c15b45c..762ef69 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.h
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -269,8 +269,7 @@
                              LayoutUnit ascent,
                              GridAxis) const;
 
-  bool BaselineMayAffectIntrinsicWidth() const;
-  bool BaselineMayAffectIntrinsicHeight() const;
+  bool BaselineMayAffectIntrinsicSize(GridTrackSizingDirection) const;
   void ComputeBaselineAlignmentContext();
   void UpdateBaselineAlignmentContextIfNeeded(LayoutBox&, GridAxis);
 
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/loader/resource/ImageResourceContent.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp
index 48efe30..7bf12629 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp
@@ -367,18 +367,16 @@
       break;
 
     case ResourceStatus::kCached:
+    case ResourceStatus::kLoadError:
+    case ResourceStatus::kDecodeError:
       // Second (or later) part of a multipart image.
+      // TODO(hiroshige): Assert that this is actually a multipart image.
       break;
 
     case ResourceStatus::kNotStarted:
       // Should have updated to kPending via NotifyStartLoad().
       CHECK(false);
       break;
-
-    case ResourceStatus::kLoadError:
-    case ResourceStatus::kDecodeError:
-      CHECK(false);
-      break;
   }
 
   // Updates the status.
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp
index f067d17..0a7e42ab 100644
--- a/third_party/WebKit/Source/core/page/DragController.cpp
+++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -627,7 +627,7 @@
               : DeleteMode::kSimple;
       const InsertMode insert_mode =
           (delete_mode == DeleteMode::kSmart &&
-           inner_frame->Selection().Granularity() == kWordGranularity &&
+           inner_frame->Selection().Granularity() == TextGranularity::kWord &&
            drag_data->CanSmartReplace())
               ? InsertMode::kSmart
               : InsertMode::kSimple;
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/BorderStyle.h b/third_party/WebKit/Source/core/style/BorderStyle.h
index 184ef45..c7780f6 100644
--- a/third_party/WebKit/Source/core/style/BorderStyle.h
+++ b/third_party/WebKit/Source/core/style/BorderStyle.h
@@ -37,9 +37,7 @@
   friend class ComputedStyle;
 
  public:
-  BorderStyle()
-      : style_(static_cast<unsigned>(EBorderStyle::kNone)),
-        is_auto_(kOutlineIsAutoOff) {}
+  BorderStyle() : style_(static_cast<unsigned>(EBorderStyle::kNone)) {}
 
   bool NonZero() const {
     return (style_ != static_cast<unsigned>(EBorderStyle::kNone));
@@ -64,14 +62,8 @@
   EBorderStyle Style() const { return static_cast<EBorderStyle>(style_); }
   void SetStyle(EBorderStyle style) { style_ = static_cast<unsigned>(style); }
 
-  OutlineIsAuto IsAuto() const { return static_cast<OutlineIsAuto>(is_auto_); }
-  void SetIsAuto(OutlineIsAuto is_auto) { is_auto_ = is_auto; }
-
  protected:
   unsigned style_ : 4;  // EBorderStyle
-
-  // This is only used by OutlineValue but moved here to keep the bits packed.
-  unsigned is_auto_ : 1;  // OutlineIsAuto
 };
 
 }  // namespace blink
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/core/timing/PerformanceNavigationTiming.cpp b/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.cpp
index df433a2..d5a34fe 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.cpp
@@ -22,11 +22,11 @@
     PerformanceServerTimingVector& serverTiming)
     : PerformanceResourceTiming(info ? info->InitialURL().GetString() : "",
                                 "navigation",
+                                time_origin,
                                 0.0,
                                 0.0,
                                 serverTiming),
       ContextClient(frame),
-      time_origin_(time_origin),
       resource_timing_info_(info) {
   DCHECK(frame);
   DCHECK(info);
@@ -143,7 +143,7 @@
       !timing->HasSameOriginAsPreviousDocument())
     return 0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->UnloadEventStart(),
+      TimeOrigin(), timing->UnloadEventStart(),
       false /* allow_negative_value */);
 }
 
@@ -155,7 +155,7 @@
       !timing->HasSameOriginAsPreviousDocument())
     return 0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->UnloadEventEnd(), false /* allow_negative_value */);
+      TimeOrigin(), timing->UnloadEventEnd(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::domInteractive() const {
@@ -163,7 +163,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->DomInteractive(), false /* allow_negative_value */);
+      TimeOrigin(), timing->DomInteractive(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::domContentLoadedEventStart()
@@ -172,7 +172,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->DomContentLoadedEventStart(),
+      TimeOrigin(), timing->DomContentLoadedEventStart(),
       false /* allow_negative_value */);
 }
 
@@ -182,7 +182,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->DomContentLoadedEventEnd(),
+      TimeOrigin(), timing->DomContentLoadedEventEnd(),
       false /* allow_negative_value */);
 }
 
@@ -191,7 +191,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->DomComplete(), false /* allow_negative_value */);
+      TimeOrigin(), timing->DomComplete(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::loadEventStart() const {
@@ -199,7 +199,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->LoadEventStart(), false /* allow_negative_value */);
+      TimeOrigin(), timing->LoadEventStart(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::loadEventEnd() const {
@@ -207,7 +207,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->LoadEventEnd(), false /* allow_negative_value */);
+      TimeOrigin(), timing->LoadEventEnd(), false /* allow_negative_value */);
 }
 
 AtomicString PerformanceNavigationTiming::type() const {
@@ -232,7 +232,7 @@
   if (!allow_redirect_details || !timing)
     return 0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->RedirectStart(), false /* allow_negative_value */);
+      TimeOrigin(), timing->RedirectStart(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::redirectEnd() const {
@@ -241,7 +241,7 @@
   if (!allow_redirect_details || !timing)
     return 0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->RedirectEnd(), false /* allow_negative_value */);
+      TimeOrigin(), timing->RedirectEnd(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::fetchStart() const {
@@ -249,7 +249,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->FetchStart(), false /* allow_negative_value */);
+      TimeOrigin(), timing->FetchStart(), false /* allow_negative_value */);
 }
 
 DOMHighResTimeStamp PerformanceNavigationTiming::responseEnd() const {
@@ -257,7 +257,7 @@
   if (!timing)
     return 0.0;
   return PerformanceBase::MonotonicTimeToDOMHighResTimeStamp(
-      time_origin_, timing->ResponseEnd(), false /* allow_negative_value */);
+      TimeOrigin(), timing->ResponseEnd(), false /* allow_negative_value */);
 }
 
 // Overriding PerformanceEntry's attributes.
diff --git a/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.h b/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.h
index 62050d4..22b6bf22 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.h
+++ b/third_party/WebKit/Source/core/timing/PerformanceNavigationTiming.h
@@ -84,7 +84,6 @@
   AtomicString AlpnNegotiatedProtocol() const override;
   AtomicString ConnectionInfo() const override;
 
-  double time_origin_;
   RefPtr<ResourceTimingInfo> resource_timing_info_;
 };
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
index 20cb249..db9156a 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
@@ -77,10 +77,12 @@
 PerformanceResourceTiming::PerformanceResourceTiming(
     const String& name,
     const String& entry_type,
+    double time_origin,
     double start_time,
     double duration,
     PerformanceServerTimingVector& serverTiming)
     : PerformanceEntry(name, entry_type, start_time, duration),
+      time_origin_(time_origin),
       serverTiming_(serverTiming) {}
 
 PerformanceResourceTiming::~PerformanceResourceTiming() {}
diff --git a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.h b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.h
index 805add0..66f6002 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.h
+++ b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.h
@@ -101,12 +101,16 @@
   // Related doc: https://goo.gl/uNecAj.
   PerformanceResourceTiming(const String& name,
                             const String& entry_type,
+                            double time_origin,
                             double start_time,
                             double duration,
                             PerformanceServerTimingVector&);
   virtual AtomicString AlpnNegotiatedProtocol() const;
   virtual AtomicString ConnectionInfo() const;
 
+ protected:
+  double TimeOrigin() const { return time_origin_; }
+
  private:
   PerformanceResourceTiming(const ResourceTimingInfo&,
                             double time_origin,
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.idl b/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.idl
index d7f514f..3e9922e 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.idl
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.idl
@@ -34,7 +34,7 @@
     Global=(Worker,DedicatedWorker),
     Exposed=DedicatedWorker
 ] interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
-    [PostMessage, RaisesException] void postMessage(any message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(any message, optional sequence<object> transfer = []);
 
     void close();
 
diff --git a/third_party/WebKit/Source/core/workers/Worker.idl b/third_party/WebKit/Source/core/workers/Worker.idl
index 8662472c..ecc43b10 100644
--- a/third_party/WebKit/Source/core/workers/Worker.idl
+++ b/third_party/WebKit/Source/core/workers/Worker.idl
@@ -37,8 +37,7 @@
 ] interface Worker : EventTarget {
     void terminate();
 
-    // TODO(foolip): The SerializedScriptValue type should be any.
-    [PostMessage, RaisesException] void postMessage(SerializedScriptValue message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(any message, optional sequence<object> transfer);
     attribute EventHandler onmessage;
 };
 
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/compositorworker/CompositorWorker.idl b/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.idl
index d864d29..6bd6a22 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.idl
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorker.idl
@@ -11,7 +11,7 @@
     RuntimeEnabled=CompositorWorker
 ] interface CompositorWorker : EventTarget {
     attribute EventHandler onmessage;
-    [PostMessage, RaisesException] void postMessage(SerializedScriptValue message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(any message, optional sequence<object> transfer = []);
     void terminate();
 };
 
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.idl b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.idl
index 9a665247..648c112 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.idl
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.idl
@@ -7,7 +7,7 @@
     Global=CompositorWorker,
     RuntimeEnabled=CompositorWorker
 ] interface CompositorWorkerGlobalScope : WorkerGlobalScope {
-    [PostMessage, RaisesException] void postMessage(any message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(any message, optional sequence<object> transfer = []);
     attribute EventHandler onmessage;
 
     long requestAnimationFrame(FrameRequestCallback callback);
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
index 7878372..eb55689 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
@@ -30,6 +30,7 @@
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/WebEncryptedMediaClient.h"
 #include "public/platform/WebEncryptedMediaRequest.h"
+#include "public/platform/WebFeaturePolicyFeature.h"
 #include "public/platform/WebMediaKeySystemConfiguration.h"
 #include "public/platform/WebMediaKeySystemMediaCapability.h"
 #include "public/platform/WebVector.h"
@@ -330,6 +331,8 @@
   UseCounter::Count(*document, WebFeature::kEncryptedMediaSecureOrigin);
   UseCounter::CountCrossOriginIframe(
       *document, WebFeature::kEncryptedMediaCrossOriginIframe);
+  Deprecation::CountDeprecationFeaturePolicy(*document,
+                                             WebFeaturePolicyFeature::kEme);
 
   // 4. Let origin be the origin of document.
   //    (Passed with the execution context.)
diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
index fba227d..f483a7e 100644
--- a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
@@ -41,6 +41,7 @@
 #include "platform/wtf/Assertions.h"
 #include "platform/wtf/CurrentTime.h"
 #include "public/platform/Platform.h"
+#include "public/platform/WebFeaturePolicyFeature.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
 namespace blink {
@@ -151,6 +152,8 @@
     UseCounter::Count(document, WebFeature::kGeolocationSecureOrigin);
     UseCounter::CountCrossOriginIframe(
         *document, WebFeature::kGeolocationSecureOriginIframe);
+    Deprecation::CountDeprecationFeaturePolicy(
+        *document, WebFeaturePolicyFeature::kGeolocation);
   } else if (GetFrame()
                  ->GetSettings()
                  ->GetAllowGeolocationOnInsecureOrigins()) {
@@ -165,6 +168,8 @@
         WebFeature::kGeolocationInsecureOriginIframeDeprecatedNotRemoved);
     HostsUsingFeatures::CountAnyWorld(
         *document, HostsUsingFeatures::Feature::kGeolocationInsecureHost);
+    Deprecation::CountDeprecationFeaturePolicy(
+        *document, WebFeaturePolicyFeature::kGeolocation);
   } else {
     Deprecation::CountDeprecation(document,
                                   WebFeature::kGeolocationInsecureOrigin);
@@ -496,46 +501,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 +547,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/mediastream/UserMediaRequest.cpp b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
index a69f4f2..e08cc59 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
@@ -48,6 +48,7 @@
 #include "modules/mediastream/UserMediaController.h"
 #include "platform/mediastream/MediaStreamCenter.h"
 #include "platform/mediastream/MediaStreamDescriptor.h"
+#include "public/platform/WebFeaturePolicyFeature.h"
 
 namespace blink {
 
@@ -402,6 +403,15 @@
                       WebFeature::kGetUserMediaSecureOrigin);
     UseCounter::CountCrossOriginIframe(
         *document, WebFeature::kGetUserMediaSecureOriginIframe);
+    if (Audio()) {
+      Deprecation::CountDeprecationFeaturePolicy(
+          *document, WebFeaturePolicyFeature::kMicrophone);
+    }
+    if (Video()) {
+      Deprecation::CountDeprecationFeaturePolicy(
+          *document, WebFeaturePolicyFeature::kCamera);
+    }
+
     HostsUsingFeatures::CountAnyWorld(
         *document, HostsUsingFeatures::Feature::kGetUserMediaSecureHost);
     return true;
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/modules/serviceworkers/Client.idl b/third_party/WebKit/Source/modules/serviceworkers/Client.idl
index b5eef12..2761202 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/Client.idl
+++ b/third_party/WebKit/Source/modules/serviceworkers/Client.idl
@@ -10,7 +10,7 @@
     readonly attribute USVString url;
     readonly attribute DOMString id;
     readonly attribute ClientType type;
-    [PostMessage, RaisesException, CallWith=ScriptState] void postMessage(SerializedScriptValue message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException, CallWith=ScriptState] void postMessage(any message, optional sequence<object> transfer);
 
     // FIXME: frameType is non-standard, see https://crbug.com/697110
     [CallWith=ScriptState] readonly attribute ContextFrameType frameType;
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.idl b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.idl
index 4c27d72..b50b4777 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.idl
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorker.idl
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// https://w3c.github.io/ServiceWorker/#service-worker-interface
+// https://w3c.github.io/ServiceWorker/#serviceworker-interface
 
 enum ServiceWorkerState {
     "installing",
@@ -43,7 +43,7 @@
     DependentLifetime
 ] interface ServiceWorker : EventTarget {
 
-    [PostMessage, RaisesException] void postMessage(SerializedScriptValue message, optional sequence<Transferable> transfer);
+    [PostMessage, RaisesException] void postMessage(any message, optional sequence<object> transfer);
 
     readonly attribute USVString scriptURL;
     readonly attribute ServiceWorkerState  state;
diff --git a/third_party/WebKit/Source/modules/webdatabase/BUILD.gn b/third_party/WebKit/Source/modules/webdatabase/BUILD.gn
index d4b6398..9ec489d 100644
--- a/third_party/WebKit/Source/modules/webdatabase/BUILD.gn
+++ b/third_party/WebKit/Source/modules/webdatabase/BUILD.gn
@@ -80,4 +80,7 @@
   } else if (is_posix) {
     sources += [ "sqlite/SQLiteFileSystemPosix.cpp" ]
   }
+
+  # Expose chromium_sqlite3_* functions from Chromium's patched SQLite.
+  defines = [ "CHROMIUM_SQLITE_INTERNALS" ]  # So that sqlite3.h is not included without this set.
 }
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp
index ae92d3e..778a597 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.cpp
@@ -47,11 +47,14 @@
     : db_(0),
       page_size_(-1),
       transaction_in_progress_(false),
+#if DCHECK_IS_ON()
       sharable_(false),
+#endif
       opening_thread_(0),
       open_error_(SQLITE_ERROR),
       open_error_message_(),
-      last_changes_count_(0) {}
+      last_changes_count_(0) {
+}
 
 SQLiteDatabase::~SQLiteDatabase() {
   Close();
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.h b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.h
index 2cf123e..df71e70 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.h
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteDatabase.h
@@ -96,7 +96,9 @@
   const char* LastErrorMsg();
 
   sqlite3* Sqlite3Handle() const {
+#if DCHECK_IS_ON()
     DCHECK_EQ(sharable_ || CurrentThread(), opening_thread_ || !db_);
+#endif
     return db_;
   }
 
@@ -138,7 +140,9 @@
   int page_size_;
 
   bool transaction_in_progress_;
+#if DCHECK_IS_ON()
   bool sharable_;
+#endif
 
   Mutex authorizer_lock_;
   CrossThreadPersistent<DatabaseAuthorizer> authorizer_;
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
index 794ad460..8ff40bd0 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemPosix.cpp
@@ -28,9 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// Expose chromium_sqlite3_* functions from Chromium's patched SQLite.
-#define CHROMIUM_SQLITE_INTERNALS
-
 #include "modules/webdatabase/sqlite/SQLiteFileSystem.h"
 
 #include "public/platform/Platform.h"
diff --git a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemWin.cpp b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemWin.cpp
index 2abe9eb..a707cca 100644
--- a/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemWin.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/sqlite/SQLiteFileSystemWin.cpp
@@ -28,9 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// Expose chromium_sqlite3_* functions from Chromium's patched SQLite.
-#define CHROMIUM_SQLITE_INTERNALS
-
 #include "modules/webdatabase/sqlite/SQLiteFileSystem.h"
 
 #include <windows.h>
diff --git a/third_party/WebKit/Source/modules/webmidi/NavigatorWebMIDI.cpp b/third_party/WebKit/Source/modules/webmidi/NavigatorWebMIDI.cpp
index ad4478cb..ac73ae61 100644
--- a/third_party/WebKit/Source/modules/webmidi/NavigatorWebMIDI.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/NavigatorWebMIDI.cpp
@@ -35,11 +35,13 @@
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/frame/Deprecation.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Navigator.h"
 #include "core/frame/UseCounter.h"
 #include "modules/webmidi/MIDIAccessInitializer.h"
 #include "modules/webmidi/MIDIOptions.h"
+#include "public/platform/WebFeaturePolicyFeature.h"
 
 namespace blink {
 
@@ -91,6 +93,9 @@
   }
   UseCounter::CountCrossOriginIframe(
       document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
+  Deprecation::CountDeprecationFeaturePolicy(
+      document, WebFeaturePolicyFeature::kMidiFeature);
+
   return MIDIAccessInitializer::Start(script_state, options);
 }
 
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/PngFuzzer.cpp b/third_party/WebKit/Source/platform/PngFuzzer.cpp
index 8898d67..19d4bb91 100644
--- a/third_party/WebKit/Source/platform/PngFuzzer.cpp
+++ b/third_party/WebKit/Source/platform/PngFuzzer.cpp
@@ -24,7 +24,7 @@
 // For more details, see
 // https://chromium.googlesource.com/chromium/src/+/master/testing/libfuzzer/README.md
 
-#include "platform/image-decoders/png/PNGImageDecoder.cpp"
+#include "platform/image-decoders/png/PNGImageDecoder.h"
 #include "platform/testing/BlinkFuzzerTestSupport.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/audio/AudioArray.h b/third_party/WebKit/Source/platform/audio/AudioArray.h
index 024dcf3..7ef1da4b 100644
--- a/third_party/WebKit/Source/platform/audio/AudioArray.h
+++ b/third_party/WebKit/Source/platform/audio/AudioArray.h
@@ -62,7 +62,7 @@
 
     unsigned initial_size = sizeof(T) * n;
 
-#if USE(WEBAUDIO_FFMPEG) || USE(WEBAUDIO_OPENMAX_DL_FFT)
+#if defined(WTF_USE_WEBAUDIO_FFMPEG) || defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
     const size_t kAlignment = 32;
 #else
     const size_t kAlignment = 16;
diff --git a/third_party/WebKit/Source/platform/audio/FFTFrame.h b/third_party/WebKit/Source/platform/audio/FFTFrame.h
index 814ea01e..84d16591 100644
--- a/third_party/WebKit/Source/platform/audio/FFTFrame.h
+++ b/third_party/WebKit/Source/platform/audio/FFTFrame.h
@@ -40,9 +40,9 @@
 
 #if defined(OS_MACOSX)
 #include <Accelerate/Accelerate.h>
-#elif USE(WEBAUDIO_OPENMAX_DL_FFT)
+#elif defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
 #include <dl/sp/api/omxSP.h>
-#elif USE(WEBAUDIO_FFMPEG)
+#elif defined(WTF_USE_WEBAUDIO_FFMPEG)
 struct RDFTContext;
 #endif
 
@@ -108,13 +108,13 @@
   static FFTSetup* fft_setups_;
   FFTSetup fft_setup_;
   DSPSplitComplex frame_;
-#elif USE(WEBAUDIO_FFMPEG)
+#elif defined(WTF_USE_WEBAUDIO_FFMPEG)
   static RDFTContext* ContextForSize(unsigned fft_size, int trans);
   RDFTContext* forward_context_;
   RDFTContext* inverse_context_;
   float* GetUpToDateComplexData();
   AudioFloatArray complex_data_;
-#elif USE(WEBAUDIO_OPENMAX_DL_FFT)
+#elif defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
   static OMXFFTSpec_R_F32* ContextForSize(unsigned log2fft_size);
   OMXFFTSpec_R_F32* forward_context_;
   OMXFFTSpec_R_F32* inverse_context_;
diff --git a/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp b/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
index f08937a..9c35263 100644
--- a/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
+++ b/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
@@ -26,10 +26,9 @@
 // FFTFrame stub implementation to avoid link errors during bringup
 
 #include "build/build_config.h"
-#include "platform/wtf/build_config.h"
 
-#if !defined(OS_MACOSX) && !USE(WEBAUDIO_FFMPEG) && \
-    !USE(WEBAUDIO_OPENMAX_DL_FFT)
+#if !defined(OS_MACOSX) && !defined(WTF_USE_WEBAUDIO_FFMPEG) && \
+    !defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
 
 #include "platform/audio/FFTFrame.h"
 
@@ -71,5 +70,5 @@
 
 }  // namespace blink
 
-#endif  // !defined(OS_MACOSX) && !USE(WEBAUDIO_FFMPEG) &&
-        // !USE(WEBAUDIO_OPENMAX_DL_FFT)
+#endif  // !defined(OS_MACOSX) && !defined(WTF_USE_WEBAUDIO_FFMPEG) &&
+        // !defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
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/audio/android/FFTFrameOpenMAXDLAndroid.cpp b/third_party/WebKit/Source/platform/audio/android/FFTFrameOpenMAXDLAndroid.cpp
index b6e0981b..5bf05a6e 100644
--- a/third_party/WebKit/Source/platform/audio/android/FFTFrameOpenMAXDLAndroid.cpp
+++ b/third_party/WebKit/Source/platform/audio/android/FFTFrameOpenMAXDLAndroid.cpp
@@ -25,7 +25,7 @@
 #include "build/build_config.h"
 #include "platform/wtf/build_config.h"
 
-#if defined(OS_ANDROID) && USE(WEBAUDIO_OPENMAX_DL_FFT)
+#if defined(OS_ANDROID) && defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
 
 #include "platform/audio/FFTFrame.h"
 
@@ -158,4 +158,4 @@
 
 }  // namespace blink
 
-#endif  // #if defined(OS_ANDROID) && !USE(WEBAUDIO_OPENMAX_DL_FFT)
+#endif  // #if defined(OS_ANDROID) && !defined(WTF_USE_WEBAUDIO_OPENMAX_DL_FFT)
diff --git a/third_party/WebKit/Source/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp b/third_party/WebKit/Source/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp
index b4de739..f1a06f3e 100644
--- a/third_party/WebKit/Source/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp
+++ b/third_party/WebKit/Source/platform/audio/ffmpeg/FFTFrameFFMPEG.cpp
@@ -26,9 +26,7 @@
 // FFTFrame implementation using FFmpeg's RDFT algorithm,
 // suitable for use on Windows and Linux.
 
-#include "platform/wtf/build_config.h"
-
-#if USE(WEBAUDIO_FFMPEG)
+#if defined(WTF_USE_WEBAUDIO_FFMPEG)
 
 #include "platform/audio/FFTFrame.h"
 
@@ -163,4 +161,4 @@
 
 }  // namespace blink
 
-#endif  // USE(WEBAUDIO_FFMPEG)
+#endif  // defined(WTF_USE_WEBAUDIO_FFMPEG)
diff --git a/third_party/WebKit/Source/platform/exported/WebHTTPBody.cpp b/third_party/WebKit/Source/platform/exported/WebHTTPBody.cpp
index 1472b010..32f91b6 100644
--- a/third_party/WebKit/Source/platform/exported/WebHTTPBody.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebHTTPBody.cpp
@@ -35,21 +35,16 @@
 
 namespace blink {
 
-class WebHTTPBodyPrivate : public EncodedFormData {};
-
 void WebHTTPBody::Initialize() {
-  Assign(static_cast<WebHTTPBodyPrivate*>(EncodedFormData::Create().LeakRef()));
+  private_ = EncodedFormData::Create();
 }
 
 void WebHTTPBody::Reset() {
-  Assign(0);
+  private_ = nullptr;
 }
 
 void WebHTTPBody::Assign(const WebHTTPBody& other) {
-  WebHTTPBodyPrivate* p = const_cast<WebHTTPBodyPrivate*>(other.private_);
-  if (p)
-    p->Ref();
-  Assign(p);
+  private_ = other.private_;
 }
 
 size_t WebHTTPBody::ElementCount() const {
@@ -158,28 +153,21 @@
 }
 
 WebHTTPBody::WebHTTPBody(RefPtr<EncodedFormData> data)
-    : private_(static_cast<WebHTTPBodyPrivate*>(data.LeakRef())) {}
+    : private_(std::move(data)) {}
 
 WebHTTPBody& WebHTTPBody::operator=(RefPtr<EncodedFormData> data) {
-  DCHECK(static_cast<WebHTTPBodyPrivate*>(data.LeakRef()));
+  private_ = std::move(data);
   return *this;
 }
 
 WebHTTPBody::operator RefPtr<EncodedFormData>() const {
-  return private_;
-}
-
-void WebHTTPBody::Assign(WebHTTPBodyPrivate* p) {
-  // p is already ref'd for us by the caller
-  if (private_)
-    private_->Deref();
-  private_ = p;
+  return private_.Get();
 }
 
 void WebHTTPBody::EnsureMutable() {
   DCHECK(!IsNull());
   if (!private_->HasOneRef())
-    Assign(static_cast<WebHTTPBodyPrivate*>(private_->Copy().LeakRef()));
+    private_ = private_->Copy();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
index bc0e908..568c394 100644
--- a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
@@ -344,6 +344,10 @@
   RuntimeEnabledFeatures::SetRenderingPipelineThrottlingEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableResourceLoadScheduler(bool enable) {
+  RuntimeEnabledFeatures::SetResourceLoadSchedulerEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableExpensiveBackgroundTimerThrottling(bool enable) {
   RuntimeEnabledFeatures::SetExpensiveBackgroundTimerThrottlingEnabled(enable);
 }
diff --git a/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp b/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
index 141d00a..c512926 100644
--- a/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
@@ -37,8 +37,6 @@
 
 namespace blink {
 
-class WebSecurityOriginPrivate : public SecurityOrigin {};
-
 WebSecurityOrigin WebSecurityOrigin::CreateFromString(const WebString& origin) {
   return WebSecurityOrigin(SecurityOrigin::CreateFromString(origin));
 }
@@ -61,15 +59,11 @@
 }
 
 void WebSecurityOrigin::Reset() {
-  Assign(0);
+  private_ = nullptr;
 }
 
 void WebSecurityOrigin::Assign(const WebSecurityOrigin& other) {
-  WebSecurityOriginPrivate* p =
-      const_cast<WebSecurityOriginPrivate*>(other.private_);
-  if (p)
-    p->Ref();
-  Assign(p);
+  private_ = other.private_;
 }
 
 WebString WebSecurityOrigin::Protocol() const {
@@ -107,7 +101,7 @@
 bool WebSecurityOrigin::CanAccess(const WebSecurityOrigin& other) const {
   DCHECK(private_);
   DCHECK(other.private_);
-  return private_->CanAccess(other.private_);
+  return private_->CanAccess(other.private_.Get());
 }
 
 bool WebSecurityOrigin::CanRequest(const WebURL& url) const {
@@ -131,28 +125,20 @@
 }
 
 WebSecurityOrigin::WebSecurityOrigin(WTF::RefPtr<SecurityOrigin> origin)
-    : private_(static_cast<WebSecurityOriginPrivate*>(origin.LeakRef())) {}
+    : private_(std::move(origin)) {}
 
 WebSecurityOrigin& WebSecurityOrigin::operator=(
     WTF::RefPtr<SecurityOrigin> origin) {
-  Assign(static_cast<WebSecurityOriginPrivate*>(origin.LeakRef()));
+  private_ = std::move(origin);
   return *this;
 }
 
 WebSecurityOrigin::operator WTF::RefPtr<SecurityOrigin>() const {
-  return RefPtr<SecurityOrigin>(
-      const_cast<WebSecurityOriginPrivate*>(private_));
+  return private_.Get();
 }
 
 SecurityOrigin* WebSecurityOrigin::Get() const {
-  return private_;
-}
-
-void WebSecurityOrigin::Assign(WebSecurityOriginPrivate* p) {
-  // p is already ref'd for us by the caller
-  if (private_)
-    private_->Deref();
-  private_ = p;
+  return private_.Get();
 }
 
 void WebSecurityOrigin::GrantLoadLocalResources() const {
diff --git a/third_party/WebKit/Source/platform/geometry/FloatPoint.h b/third_party/WebKit/Source/platform/geometry/FloatPoint.h
index 42538c8b..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/GraphicsTypes.h b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
index 365cb14d..96f2b9cf 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
@@ -50,7 +50,7 @@
   kInterpolationLow = kLow_SkFilterQuality,
   kInterpolationMedium = kMedium_SkFilterQuality,
   kInterpolationHigh = kHigh_SkFilterQuality,
-#if USE(LOW_QUALITY_IMAGE_INTERPOLATION)
+#if defined(WTF_USE_LOW_QUALITY_IMAGE_INTERPOLATION)
   kInterpolationDefault = kInterpolationLow,
 #else
   kInterpolationDefault = kInterpolationHigh,
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
index 013f87c..cf013338 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
@@ -8,9 +8,9 @@
 #include <memory>
 #include "cc/ipc/compositor_frame_sink.mojom-blink.h"
 #include "cc/output/begin_frame_args.h"
-#include "cc/resources/shared_bitmap.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface_id.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "platform/graphics/OffscreenCanvasFrameDispatcher.h"
 #include "platform/graphics/StaticBitmapImage.h"
@@ -75,7 +75,7 @@
 
   struct FrameResource {
     RefPtr<StaticBitmapImage> image_;
-    std::unique_ptr<cc::SharedBitmap> shared_bitmap_;
+    std::unique_ptr<viz::SharedBitmap> shared_bitmap_;
     GLuint texture_id_ = 0;
     GLuint image_id_ = 0;
     bool spare_lock_ = true;
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/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
index 8dd4bce..2a0d33c 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -34,7 +34,7 @@
 #include <memory>
 
 #include "build/build_config.h"
-#include "cc/resources/shared_bitmap.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
@@ -234,7 +234,7 @@
   return !want_alpha_channel_ && rgb_emulation;
 }
 
-std::unique_ptr<cc::SharedBitmap> DrawingBuffer::CreateOrRecycleBitmap() {
+std::unique_ptr<viz::SharedBitmap> DrawingBuffer::CreateOrRecycleBitmap() {
   auto it = std::remove_if(
       recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
       [this](const RecycledBitmap& bitmap) { return bitmap.size != size_; });
@@ -299,7 +299,7 @@
     cc::TextureMailbox* out_mailbox,
     std::unique_ptr<cc::SingleReleaseCallback>* out_release_callback) {
   DCHECK(state_restorer_);
-  std::unique_ptr<cc::SharedBitmap> bitmap = CreateOrRecycleBitmap();
+  std::unique_ptr<viz::SharedBitmap> bitmap = CreateOrRecycleBitmap();
   if (!bitmap)
     return false;
 
@@ -449,7 +449,7 @@
 }
 
 void DrawingBuffer::MailboxReleasedSoftware(
-    std::unique_ptr<cc::SharedBitmap> bitmap,
+    std::unique_ptr<viz::SharedBitmap> bitmap,
     const IntSize& size,
     const gpu::SyncToken& sync_token,
     bool lost_resource) {
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
index 0ec932537cf..3644969 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
@@ -47,10 +47,6 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/color_space.h"
 
-namespace cc {
-class SharedBitmap;
-}
-
 namespace gfx {
 class GpuMemoryBuffer;
 }
@@ -61,6 +57,10 @@
 }
 }
 
+namespace viz {
+class SharedBitmap;
+}
+
 namespace WTF {
 class ArrayBufferContents;
 }
@@ -260,7 +260,7 @@
   // Shared memory bitmaps that were released by the compositor and can be used
   // again by this DrawingBuffer.
   struct RecycledBitmap {
-    std::unique_ptr<cc::SharedBitmap> bitmap;
+    std::unique_ptr<viz::SharedBitmap> bitmap;
     IntSize size;
   };
   Vector<RecycledBitmap> recycled_bitmaps_;
@@ -381,7 +381,7 @@
   void MailboxReleasedGpu(RefPtr<ColorBuffer>,
                           const gpu::SyncToken&,
                           bool lost_resource);
-  void MailboxReleasedSoftware(std::unique_ptr<cc::SharedBitmap>,
+  void MailboxReleasedSoftware(std::unique_ptr<viz::SharedBitmap>,
                                const IntSize&,
                                const gpu::SyncToken&,
                                bool lost_resource);
@@ -399,7 +399,7 @@
 
   void ClearPlatformLayer();
 
-  std::unique_ptr<cc::SharedBitmap> CreateOrRecycleBitmap();
+  std::unique_ptr<viz::SharedBitmap> CreateOrRecycleBitmap();
 
   // Updates the current size of the buffer, ensuring that
   // s_currentResourceUsePixels is updated.
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp
index f53088b..4a84e0a 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.cpp
@@ -4,8 +4,8 @@
 
 #include "platform/graphics/gpu/ImageLayerBridge.h"
 
-#include "cc/resources/shared_bitmap.h"
 #include "cc/resources/texture_mailbox.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "platform/graphics/ColorBehavior.h"
 #include "platform/graphics/GraphicsLayer.h"
@@ -87,7 +87,7 @@
     *out_release_callback = cc::SingleReleaseCallback::Create(
         ConvertToBaseCallback(std::move(func)));
   } else {
-    std::unique_ptr<cc::SharedBitmap> bitmap = CreateOrRecycleBitmap();
+    std::unique_ptr<viz::SharedBitmap> bitmap = CreateOrRecycleBitmap();
     if (!bitmap)
       return false;
 
@@ -123,7 +123,7 @@
   return true;
 }
 
-std::unique_ptr<cc::SharedBitmap> ImageLayerBridge::CreateOrRecycleBitmap() {
+std::unique_ptr<viz::SharedBitmap> ImageLayerBridge::CreateOrRecycleBitmap() {
   auto it = std::remove_if(recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
                            [this](const RecycledBitmap& bitmap) {
                              return bitmap.size != image_->Size();
@@ -161,7 +161,7 @@
 }
 
 void ImageLayerBridge::MailboxReleasedSoftware(
-    std::unique_ptr<cc::SharedBitmap> bitmap,
+    std::unique_ptr<viz::SharedBitmap> bitmap,
     const IntSize& size,
     const gpu::SyncToken& sync_token,
     bool lost_resource) {
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.h b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.h
index 3e248ad7..31f9d435 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/ImageLayerBridge.h
@@ -10,7 +10,7 @@
 #include "platform/graphics/StaticBitmapImage.h"
 #include "platform/heap/Heap.h"
 
-namespace cc {
+namespace viz {
 class SharedBitmap;
 }
 
@@ -40,7 +40,7 @@
                           const gpu::SyncToken&,
                           bool lost_resource);
 
-  void MailboxReleasedSoftware(std::unique_ptr<cc::SharedBitmap>,
+  void MailboxReleasedSoftware(std::unique_ptr<viz::SharedBitmap>,
                                const IntSize&,
                                const gpu::SyncToken&,
                                bool lost_resource);
@@ -58,7 +58,7 @@
   DEFINE_INLINE_TRACE() {}
 
  private:
-  std::unique_ptr<cc::SharedBitmap> CreateOrRecycleBitmap();
+  std::unique_ptr<viz::SharedBitmap> CreateOrRecycleBitmap();
 
   RefPtr<StaticBitmapImage> image_;
   std::unique_ptr<WebExternalTextureLayer> layer_;
@@ -67,7 +67,7 @@
   // Shared memory bitmaps that were released by the compositor and can be used
   // again by this ImageLayerBridge.
   struct RecycledBitmap {
-    std::unique_ptr<cc::SharedBitmap> bitmap;
+    std::unique_ptr<viz::SharedBitmap> bitmap;
     IntSize size;
   };
   Vector<RecycledBitmap> recycled_bitmaps_;
diff --git a/third_party/WebKit/Source/platform/loader/DEPS b/third_party/WebKit/Source/platform/loader/DEPS
index 94e6bc5..b78c176 100644
--- a/third_party/WebKit/Source/platform/loader/DEPS
+++ b/third_party/WebKit/Source/platform/loader/DEPS
@@ -1,5 +1,7 @@
 include_rules = [
+    "+base/metrics/field_trial_params.h",  # for fetch/ResourceLoadScheduler.cpp
+    "+base/strings/string_number_conversions.h",  # for fetch/ResourceLoadScheduler.cpp
     "+components/link_header_util",  # for LinkHeader.cpp
     "+net/base/net_errors.h",  # for fetch/ResourceError.h
-    "+net/http/http_util.h",  # for CrossOriginAccessControl.cpp
+    "+net/http/http_util.h",  # for fetch/CrossOriginAccessControl.cpp
 ]
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index 4e37baa..57ae8de 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -1386,10 +1386,8 @@
   ResourceLoader* loader = nullptr;
 
   {
-    // Forbids JavaScript/addClient/removeClient/revalidation until start()
+    // Forbids JavaScript/revalidation until start()
     // to prevent unintended state transitions.
-    Resource::ProhibitAddRemoveClientInScope
-        prohibit_add_remove_client_in_scope(resource);
     Resource::RevalidationStartForbiddenScope
         revalidation_start_forbidden_scope(resource);
     ScriptForbiddenIfMainThreadScope script_forbidden_scope;
@@ -1431,6 +1429,10 @@
     StorePerformanceTimingInitiatorInformation(resource);
     resource->SetFetcherSecurityOrigin(source_origin);
 
+    // NotifyStartLoad() shouldn't cause AddClient/RemoveClient().
+    Resource::ProhibitAddRemoveClientInScope
+        prohibit_add_remove_client_in_scope(resource);
+
     resource->NotifyStartLoad();
   }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
index fd923936..1482ccd 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
@@ -4,14 +4,40 @@
 
 #include "platform/loader/fetch/ResourceLoadScheduler.h"
 
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_number_conversions.h"
 #include "platform/RuntimeEnabledFeatures.h"
 
 namespace blink {
 
 namespace {
 
-// TODO(toyoshim): Should be managed via field trial flag.
-constexpr size_t kOutstandingThrottledLimit = 16u;
+// Field trial name.
+const char kResourceLoadSchedulerTrial[] = "ResourceLoadScheduler";
+
+// Field trial parameter names.
+const char kOutstandingLimitForBackgroundFrameName[] = "bg_limit";
+
+// Field trial default parameters.
+constexpr size_t kOutstandingLimitForBackgroundFrameDefault = 16u;
+
+uint32_t GetFieldTrialUint32Param(const char* name, uint32_t default_param) {
+  std::map<std::string, std::string> trial_params;
+  bool result =
+      base::GetFieldTrialParams(kResourceLoadSchedulerTrial, &trial_params);
+  if (!result)
+    return default_param;
+
+  const auto& found = trial_params.find(name);
+  if (found == trial_params.end())
+    return default_param;
+
+  uint32_t param;
+  if (!base::StringToUint(found->second, &param))
+    return default_param;
+
+  return param;
+}
 
 }  // namespace
 
@@ -19,7 +45,10 @@
     ResourceLoadScheduler::kInvalidClientId;
 
 ResourceLoadScheduler::ResourceLoadScheduler(FetchContext* context)
-    : context_(context) {
+    : outstanding_throttled_limit_(
+          GetFieldTrialUint32Param(kOutstandingLimitForBackgroundFrameName,
+                                   kOutstandingLimitForBackgroundFrameDefault)),
+      context_(context) {
   DCHECK(context);
 
   if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled())
@@ -108,7 +137,7 @@
     WebFrameScheduler::ThrottlingState state) {
   switch (state) {
     case WebFrameScheduler::ThrottlingState::kThrottled:
-      SetOutstandingLimitAndMaybeRun(kOutstandingThrottledLimit);
+      SetOutstandingLimitAndMaybeRun(outstanding_throttled_limit_);
       break;
     case WebFrameScheduler::ThrottlingState::kNotThrottled:
       SetOutstandingLimitAndMaybeRun(kOutstandingUnlimited);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.h
index 0af4151b..133aff0 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.h
@@ -112,6 +112,9 @@
   // tests fail.
   size_t outstanding_limit_ = kOutstandingUnlimited;
 
+  // Outstanding limit for throttled frames. Managed via the field trial.
+  const size_t outstanding_throttled_limit_;
+
   // The last used ClientId to calculate the next.
   ClientId current_id_ = kInvalidClientId;
 
diff --git a/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraitsTest.cpp b/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraitsTest.cpp
index 394bd99..2560355 100644
--- a/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraitsTest.cpp
+++ b/third_party/WebKit/Source/platform/mojo/CommonCustomTypesStructTraitsTest.cpp
@@ -21,8 +21,8 @@
 
   // TestString16 implementation:
   void BounceString16(const String& in,
-                      const BounceString16Callback& callback) override {
-    callback.Run(in);
+                      BounceString16Callback callback) override {
+    std::move(callback).Run(in);
   }
 
  private:
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/platform/wtf/Assertions.cpp b/third_party/WebKit/Source/platform/wtf/Assertions.cpp
index 8b8eb859..9bdece75 100644
--- a/third_party/WebKit/Source/platform/wtf/Assertions.cpp
+++ b/third_party/WebKit/Source/platform/wtf/Assertions.cpp
@@ -45,11 +45,7 @@
 #include "platform/wtf/Threading.h"
 
 #if defined(OS_MACOSX)
-#include <AvailabilityMacros.h>
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
-#define WTF_USE_APPLE_SYSTEM_LOG 1
 #include <asl.h>
-#endif
 #endif  // defined(OS_MACOSX)
 
 #if defined(COMPILER_MSVC)
@@ -72,7 +68,7 @@
 
 PRINTF_FORMAT(1, 0)
 static void vprintf_stderr_common(const char* format, va_list args) {
-#if defined(OS_MACOSX) && USE(APPLE_SYSTEM_LOG)
+#if defined(OS_MACOSX)
   va_list copyOfArgs;
   va_copy(copyOfArgs, args);
   asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
diff --git a/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp
index f8a84a2c..b95428b 100644
--- a/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp
+++ b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.cpp
@@ -26,7 +26,8 @@
 
 #include "platform/wtf/DynamicAnnotations.h"
 
-#if USE(DYNAMIC_ANNOTATIONS) && !USE(DYNAMIC_ANNOTATIONS_NOIMPL)
+#if defined(WTF_USE_DYNAMIC_ANNOTATIONS) && \
+    !defined(WTF_USE_DYNAMIC_ANNOTATIONS_NOIMPL)
 
 // Identical code folding(-Wl,--icf=all) countermeasures.
 // This makes all Annotate* functions different, which prevents the linker from
@@ -57,4 +58,5 @@
   DYNAMIC_ANNOTATIONS_IMPL
 }
 
-#endif  // USE(DYNAMIC_ANNOTATIONS) && !USE(DYNAMIC_ANNOTATIONS_NOIMPL)
+#endif  // defined(WTF_USE_DYNAMIC_ANNOTATIONS) &&
+        // !defined(WTF_USE_DYNAMIC_ANNOTATIONS_NOIMPL)
diff --git a/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h
index 6584c4ea..2462358 100644
--- a/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h
+++ b/third_party/WebKit/Source/platform/wtf/DynamicAnnotations.h
@@ -52,7 +52,7 @@
 #include "platform/wtf/WTFExport.h"
 #include "platform/wtf/build_config.h"
 
-#if USE(DYNAMIC_ANNOTATIONS)
+#if defined(WTF_USE_DYNAMIC_ANNOTATIONS)
 /* Tell data race detector that we're not interested in reports on the given
  * address range. */
 #define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
@@ -102,13 +102,13 @@
 }  // extern "C"
 #endif
 
-#else  // USE(DYNAMIC_ANNOTATIONS)
+#else  // defined(WTF_USE_DYNAMIC_ANNOTATIONS)
 /* These macros are empty when dynamic annotations are not enabled so you can
  * use them without affecting the performance of release binaries. */
 #define WTF_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)
 #define WTF_ANNOTATE_BENIGN_RACE(pointer, description)
 #define WTF_ANNOTATE_HAPPENS_BEFORE(address)
 #define WTF_ANNOTATE_HAPPENS_AFTER(address)
-#endif  // USE(DYNAMIC_ANNOTATIONS)
+#endif  // defined(WTF_USE_DYNAMIC_ANNOTATIONS)
 
 #endif  // WTF_DynamicAnnotations_h
diff --git a/third_party/WebKit/Source/platform/wtf/RetainPtr.h b/third_party/WebKit/Source/platform/wtf/RetainPtr.h
index 1322eb2a..64b4440a 100644
--- a/third_party/WebKit/Source/platform/wtf/RetainPtr.h
+++ b/third_party/WebKit/Source/platform/wtf/RetainPtr.h
@@ -29,10 +29,6 @@
 #include <type_traits>
 #include <utility>
 
-#if USE(CF)
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
 #ifdef __OBJC__
 #import <Foundation/Foundation.h>
 #endif
diff --git a/third_party/WebKit/Source/platform/wtf/build_config.h b/third_party/WebKit/Source/platform/wtf/build_config.h
index 4703e00..cf1551c0 100644
--- a/third_party/WebKit/Source/platform/wtf/build_config.h
+++ b/third_party/WebKit/Source/platform/wtf/build_config.h
@@ -34,13 +34,6 @@
  * present or not */
 #define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE)
 
-/* ==== Policy decision macros: these define policy choices for a particular
- * port. ==== */
-
-/* USE() - use a particular third-party library or optional OS service */
-#define USE(WTF_FEATURE) \
-  (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE)
-
 /* There is an assumption in the project that either OS_WIN or OS_POSIX is
  * set. */
 #if !defined(OS_WIN) && !defined(OS_POSIX)
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 13dec4e..6e006c5 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1251,9 +1251,9 @@
   // needs to be audited.  See http://crbug.com/590369 for more details.
   GetFrame()->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  blink::TextGranularity blink_granularity = blink::kCharacterGranularity;
+  blink::TextGranularity blink_granularity = blink::TextGranularity::kCharacter;
   if (granularity == WebFrame::kWordGranularity)
-    blink_granularity = blink::kWordGranularity;
+    blink_granularity = blink::TextGranularity::kWord;
   GetFrame()->Selection().MoveRangeSelection(
       VisiblePositionForViewportPoint(base_in_viewport),
       VisiblePositionForViewportPoint(extent_in_viewport), blink_granularity);
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index be61617..101c6de 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -174,7 +174,7 @@
 #include "public/web/WebWindowFeatures.h"
 #include "web/WebDevToolsAgentImpl.h"
 
-#if USE(DEFAULT_RENDER_THEME)
+#if defined(WTF_USE_DEFAULT_RENDER_THEME)
 #include "core/layout/LayoutThemeDefault.h"
 #endif
 
@@ -3596,7 +3596,7 @@
                                      unsigned active_foreground_color,
                                      unsigned inactive_background_color,
                                      unsigned inactive_foreground_color) {
-#if USE(DEFAULT_RENDER_THEME)
+#if defined(WTF_USE_DEFAULT_RENDER_THEME)
   LayoutThemeDefault::SetSelectionColors(
       active_background_color, active_foreground_color,
       inactive_background_color, inactive_foreground_color);
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/common/system/user.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user.py
index 1079451c..a98e285a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user.py
@@ -50,19 +50,19 @@
 
     # FIXME: These are @classmethods because bugzilla.py doesn't have a Tool object (thus no User instance).
     @classmethod
-    def prompt(cls, message, repeat=1, raw_input=raw_input):
+    def prompt(cls, message, repeat=1, input_func=raw_input):
         response = None
         while repeat and not response:
             repeat -= 1
-            response = raw_input(message)
+            response = input_func(message)
         return response
 
     @classmethod
-    def _wait_on_list_response(cls, list_items, can_choose_multiple, raw_input):
+    def _wait_on_list_response(cls, list_items, can_choose_multiple, input_func):
         while True:
             if can_choose_multiple:
                 response = cls.prompt(
-                    'Enter one or more numbers (comma-separated) or ranges (e.g. 3-7), or \'all\': ', raw_input=raw_input)
+                    'Enter one or more numbers (comma-separated) or ranges (e.g. 3-7), or \'all\': ', input_func=input_func)
                 if not response.strip() or response == 'all':
                     return list_items
 
@@ -80,25 +80,25 @@
                 return [list_items[i] for i in indices]
             else:
                 try:
-                    result = int(cls.prompt('Enter a number: ', raw_input=raw_input)) - 1
+                    result = int(cls.prompt('Enter a number: ', input_func=input_func)) - 1
                 except ValueError:
                     continue
                 return list_items[result]
 
     @classmethod
-    def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
+    def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, input_func=raw_input):
         print list_title
         i = 0
         for item in list_items:
             i += 1
             print '%2d. %s' % (i, item)
-        return cls._wait_on_list_response(list_items, can_choose_multiple, raw_input)
+        return cls._wait_on_list_response(list_items, can_choose_multiple, input_func)
 
-    def confirm(self, message=None, default=DEFAULT_YES, raw_input=raw_input):
+    def confirm(self, message=None, default=DEFAULT_YES, input_func=raw_input):
         if not message:
             message = 'Continue?'
         choice = {'y': 'Y/n', 'n': 'y/N'}[default]
-        response = raw_input('%s [%s]: ' % (message, choice))
+        response = input_func('%s [%s]: ' % (message, choice))
         response = response.strip().lower()
         if not response:
             response = default
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user_unittest.py
index f830ddc..6f71dca 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/user_unittest.py
@@ -47,7 +47,7 @@
             return None
 
         self.assertEqual(User.prompt('input', repeat=self.repeats_remaining,
-                                     raw_input=mock_raw_input), 'example user response')
+                                     input_func=mock_raw_input), 'example user response')
 
     def test_prompt_when_exceeded_repeats(self):
         self.repeats_remaining = 2
@@ -55,7 +55,7 @@
         def mock_raw_input(_):
             self.repeats_remaining -= 1
             return None
-        self.assertIsNone(User.prompt('input', repeat=self.repeats_remaining, raw_input=mock_raw_input))
+        self.assertIsNone(User.prompt('input', repeat=self.repeats_remaining, input_func=mock_raw_input))
 
     def test_prompt_with_list(self):
         def run_prompt_test(inputs, expected_result, can_choose_multiple=False):
@@ -66,7 +66,7 @@
                 self,
                 User.prompt_with_list,
                 args=['title', ['foo', 'bar']],
-                kwargs={'can_choose_multiple': can_choose_multiple, 'raw_input': mock_raw_input},
+                kwargs={'can_choose_multiple': can_choose_multiple, 'input_func': mock_raw_input},
                 expected_stdout='title\n 1. foo\n 2. bar\n')
             self.assertEqual(actual_result, expected_result)
             self.assertEqual(len(inputs), 0)
@@ -87,7 +87,7 @@
             self.assertEqual(expected_message, message)
             return user_input
 
-        out = User().confirm(default=default, raw_input=mock_raw_input)
+        out = User().confirm(default=default, input_func=mock_raw_input)
         self.assertEqual(expected_out, out)
 
     def test_confirm_input_yes(self):
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/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_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..d1fe40c6 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
@@ -1003,6 +1003,9 @@
     def inspector_build_directory(self):
         return self._build_path('resources', 'inspector')
 
+    def generated_sources_directory(self):
+        return self._build_path('gen')
+
     def apache_config_directory(self):
         return self._path_finder.path_from_tools_scripts('apache_config')
 
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..e133fdb 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 ]
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 fcc8191f..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/servers/apache_http.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py
index ccc29a7e..42a43592 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/apache_http.py
@@ -63,6 +63,7 @@
         mime_types_path = self._filesystem.join(self._port_obj.apache_config_directory(), 'mime.types')
         cert_file = self._filesystem.join(self._port_obj.apache_config_directory(), 'webkit-httpd.pem')
         inspector_sources_dir = self._port_obj.inspector_build_directory()
+        generated_sources_dir = self._port_obj.generated_sources_directory()
 
         self._access_log_path = self._filesystem.join(output_dir, 'access_log.txt')
         self._error_log_path = self._filesystem.join(output_dir, 'error_log.txt')
@@ -86,6 +87,7 @@
             '-c', 'PidFile %s' % self._pid_file,
             '-c', 'SSLCertificateFile "%s"' % cert_file,
             '-c', 'Alias /inspector-sources "%s"' % inspector_sources_dir,
+            '-c', 'Alias /gen "%s"' % generated_sources_dir,
             '-c', 'DefaultType None',
         ]
 
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_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/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 8f65863..2f3f1cf 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -774,7 +774,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"
 }
 
 mojom("android_mojo_bindings") {
@@ -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/DEPS b/third_party/WebKit/public/platform/DEPS
index 7a60c49..3835db5b 100644
--- a/third_party/WebKit/public/platform/DEPS
+++ b/third_party/WebKit/public/platform/DEPS
@@ -11,6 +11,7 @@
     "-bindings",
     "+cc",
     "-cc/blink",
+    "+components/viz/common/quads",
     "-core",
     "-modules",
     # TODO(toyoshim): Remove following media/midi direct dependency in public
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index 4d390c1..542b7ecc 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -59,8 +59,8 @@
 #include "WebVector.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/time/time.h"
-#include "cc/resources/shared_bitmap.h"
 #include "cc/surfaces/frame_sink_id.h"
+#include "components/viz/common/quads/shared_bitmap.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 
@@ -529,7 +529,7 @@
     return nullptr;
   }
 
-  virtual std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+  virtual std::unique_ptr<viz::SharedBitmap> AllocateSharedBitmap(
       const WebSize& size) {
     return nullptr;
   }
diff --git a/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h b/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
index a90defe..9e4e5f3c 100644
--- a/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
+++ b/third_party/WebKit/public/platform/WebFeaturePolicyFeature.h
@@ -10,9 +10,9 @@
 // These values map to the features which can be controlled by Feature Policy.
 //
 // Features are defined in
-// https://wicg.github.io/feature-policy/#defined-features. Many of these are
-// still under development in blink behind the featurePolicyExperimentalFeatures
-// flag, see getWebFeaturePolicyFeature().
+// https://github.com/WICG/feature-policy/blob/gh-pages/features.md. Many of
+// these are still under development in blink behind the
+// featurePolicyExperimentalFeatures flag, see getWebFeaturePolicyFeature().
 enum class WebFeaturePolicyFeature {
   kNotFound = 0,
   // Controls access to video input devices.
diff --git a/third_party/WebKit/public/platform/WebHTTPBody.h b/third_party/WebKit/public/platform/WebHTTPBody.h
index e128d189..141d616c 100644
--- a/third_party/WebKit/public/platform/WebHTTPBody.h
+++ b/third_party/WebKit/public/platform/WebHTTPBody.h
@@ -44,7 +44,6 @@
 namespace blink {
 
 class EncodedFormData;
-class WebHTTPBodyPrivate;
 
 class WebHTTPBody {
  public:
@@ -61,8 +60,8 @@
 
   ~WebHTTPBody() { Reset(); }
 
-  WebHTTPBody() : private_(0) {}
-  WebHTTPBody(const WebHTTPBody& b) : private_(0) { Assign(b); }
+  WebHTTPBody() {}
+  WebHTTPBody(const WebHTTPBody& b) { Assign(b); }
   WebHTTPBody& operator=(const WebHTTPBody& b) {
     Assign(b);
     return *this;
@@ -112,10 +111,9 @@
 #endif
 
  private:
-  BLINK_PLATFORM_EXPORT void Assign(WebHTTPBodyPrivate*);
   BLINK_PLATFORM_EXPORT void EnsureMutable();
 
-  WebHTTPBodyPrivate* private_;
+  WebPrivatePtr<EncodedFormData> private_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/WebPrivatePtr.h b/third_party/WebKit/public/platform/WebPrivatePtr.h
index 62399d7..e86b2f2 100644
--- a/third_party/WebKit/public/platform/WebPrivatePtr.h
+++ b/third_party/WebKit/public/platform/WebPrivatePtr.h
@@ -282,6 +282,7 @@
   }
 
   bool IsNull() const { return !storage_; }
+  explicit operator bool() const { return !IsNull(); }
 
 #if INSIDE_BLINK
   template <typename U>
diff --git a/third_party/WebKit/public/platform/WebRuntimeFeatures.h b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
index 1ce4008..e57d953 100644
--- a/third_party/WebKit/public/platform/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
@@ -112,8 +112,9 @@
   BLINK_PLATFORM_EXPORT static void EnablePresentationAPI(bool);
   BLINK_PLATFORM_EXPORT static void EnablePushMessaging(bool);
   BLINK_PLATFORM_EXPORT static void EnableReducedReferrerGranularity(bool);
-  BLINK_PLATFORM_EXPORT static void EnableRenderingPipelineThrottling(bool);
   BLINK_PLATFORM_EXPORT static void EnableRemotePlaybackAPI(bool);
+  BLINK_PLATFORM_EXPORT static void EnableRenderingPipelineThrottling(bool);
+  BLINK_PLATFORM_EXPORT static void EnableResourceLoadScheduler(bool);
   BLINK_PLATFORM_EXPORT static void EnableRootLayerScrolling(bool);
   BLINK_PLATFORM_EXPORT static void EnableScriptedSpeech(bool);
   BLINK_PLATFORM_EXPORT static void EnableScrollAnchoring(bool);
diff --git a/third_party/WebKit/public/platform/WebSecurityOrigin.h b/third_party/WebKit/public/platform/WebSecurityOrigin.h
index 6915c73..0cdb76a 100644
--- a/third_party/WebKit/public/platform/WebSecurityOrigin.h
+++ b/third_party/WebKit/public/platform/WebSecurityOrigin.h
@@ -32,6 +32,7 @@
 #define WebSecurityOrigin_h
 
 #include "public/platform/WebCommon.h"
+#include "public/platform/WebPrivatePtr.h"
 #include "public/platform/WebString.h"
 
 #if INSIDE_BLINK
@@ -43,15 +44,14 @@
 namespace blink {
 
 class SecurityOrigin;
-class WebSecurityOriginPrivate;
 class WebURL;
 
 class WebSecurityOrigin {
  public:
   ~WebSecurityOrigin() { Reset(); }
 
-  WebSecurityOrigin() : private_(0) {}
-  WebSecurityOrigin(const WebSecurityOrigin& s) : private_(0) { Assign(s); }
+  WebSecurityOrigin() {}
+  WebSecurityOrigin(const WebSecurityOrigin& s) { Assign(s); }
   WebSecurityOrigin& operator=(const WebSecurityOrigin& s) {
     Assign(s);
     return *this;
@@ -65,7 +65,7 @@
   BLINK_PLATFORM_EXPORT void Reset();
   BLINK_PLATFORM_EXPORT void Assign(const WebSecurityOrigin&);
 
-  bool IsNull() const { return !private_; }
+  bool IsNull() const { return private_.IsNull(); }
 
   BLINK_PLATFORM_EXPORT WebString Protocol() const;
   BLINK_PLATFORM_EXPORT WebString Host() const;
@@ -127,7 +127,7 @@
                             Suborigin().Ascii());
   }
 
-  WebSecurityOrigin(const url::Origin& origin) : private_(0) {
+  WebSecurityOrigin(const url::Origin& origin) {
     if (origin.unique()) {
       Assign(WebSecurityOrigin::CreateUnique());
       return;
@@ -150,8 +150,7 @@
       int port,
       const WebString& suborigin);
 
-  void Assign(WebSecurityOriginPrivate*);
-  WebSecurityOriginPrivate* private_;
+  WebPrivatePtr<SecurityOrigin> private_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 91dbd53..7a1b51ef 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1589,6 +1589,12 @@
   kLinearAccelerationSensorConstructor = 2051,
   kReportUriMultipleEndpoints = 2052,
   kReportUriSingleEndpoint = 2053,
+  kV8ConstructorNonUndefinedPrimitiveReturn = 2054,
+  kEncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe = 2055,
+  kGeolocationDisallowedByFeaturePolicyInCrossOriginIframe = 2056,
+  kGetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe = 2057,
+  kGetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe = 2058,
+  kRequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe = 2059,
 
   // 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/minizip/BUILD.gn b/third_party/minizip/BUILD.gn
index b7a65c2..c2c7ef883 100644
--- a/third_party/minizip/BUILD.gn
+++ b/third_party/minizip/BUILD.gn
@@ -8,6 +8,10 @@
   }
 }
 
+config("minizip_include_dirs") {
+  include_dirs = [ "//third_party/zlib" ]
+}
+
 static_library("minizip") {
   sources = [
     # TODO(yawano): AES part cannot be compiled in pnacl.
@@ -56,6 +60,8 @@
 
   configs += [ ":minizip_warnings" ]
 
+  public_configs = [ ":minizip_include_dirs" ]
+
   deps = [
     "//third_party/zlib:zlib",
   ]
@@ -63,6 +69,6 @@
   visibility = [
     # NOTE: Modifying visibility list requires approval from security team.
     "//testing/libfuzzer/fuzzers:*",
-    "//ui/file_manager/zip_archiver/cpp:zip_archiver_pnacl",
+    "//chrome/browser/resources/chromeos/zip_archiver/cpp:zip_archiver_pnacl",
   ]
 }
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/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
index d029291..3aff656 100644
--- a/tools/gn/xcode_writer.cc
+++ b/tools/gn/xcode_writer.cc
@@ -219,6 +219,46 @@
   }
 }
 
+// Add all source files for indexing, both private and public.
+void AddSourceFilesToProjectForIndexing(
+    const std::vector<const Target*>& targets,
+    PBXProject* project,
+    SourceDir source_dir,
+    const BuildSettings* build_settings) {
+  std::vector<SourceFile> sources;
+  for (const Target* target : targets) {
+    for (const SourceFile& source : target->sources()) {
+      if (IsStringInOutputDir(build_settings->build_dir(), source.value()))
+        continue;
+
+      sources.push_back(source);
+    }
+
+    if (target->all_headers_public())
+      continue;
+
+    for (const SourceFile& source : target->public_headers()) {
+      if (IsStringInOutputDir(build_settings->build_dir(), source.value()))
+        continue;
+
+      sources.push_back(source);
+    }
+  }
+
+  // Sort sources to ensure determinism of the project file generation and
+  // remove duplicate reference to the source files (can happen due to the
+  // bundle_data targets).
+  std::sort(sources.begin(), sources.end());
+  sources.erase(std::unique(sources.begin(), sources.end()), sources.end());
+
+  for (const SourceFile& source : sources) {
+    std::string source_file = RebasePath(source.value(), source_dir,
+                                         build_settings->root_path_utf8());
+    project->AddSourceFileToIndexingTarget(source_file, source_file,
+                                           CompilerFlags::NONE);
+  }
+}
+
 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor {
  public:
   CollectPBXObjectsPerClassHelper() {}
@@ -419,41 +459,10 @@
     TargetOsType target_os) {
   std::unique_ptr<PBXProject> main_project(
       new PBXProject("products", config_name, source_path, attributes));
+
   SourceDir source_dir("//");
-
-  // Add all source files for indexing, both private and public.
-  std::vector<SourceFile> sources;
-  for (const Target* target : all_targets) {
-    for (const SourceFile& source : target->sources()) {
-      if (IsStringInOutputDir(build_settings->build_dir(), source.value()))
-        continue;
-
-      sources.push_back(source);
-    }
-
-    if (target->all_headers_public())
-      continue;
-
-    for (const SourceFile& source : target->public_headers()) {
-      if (IsStringInOutputDir(build_settings->build_dir(), source.value()))
-        continue;
-
-      sources.push_back(source);
-    }
-  }
-
-  // Sort sources to ensure determinisn of the project file generation and
-  // remove duplicate reference to the source files (can happen due to the
-  // bundle_data targets).
-  std::sort(sources.begin(), sources.end());
-  sources.erase(std::unique(sources.begin(), sources.end()), sources.end());
-
-  for (const SourceFile& source : sources) {
-    std::string source_file = RebasePath(source.value(), source_dir,
-                                         build_settings->root_path_utf8());
-    main_project->AddSourceFileToIndexingTarget(source_file, source_file,
-                                                CompilerFlags::NONE);
-  }
+  AddSourceFilesToProjectForIndexing(all_targets, main_project.get(),
+                                     source_dir, build_settings);
 
   // Filter xctest module and application targets and find list of xctest files
   // recursively under them.
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..0c8a9641 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15765,6 +15765,17 @@
   <int value="2051" label="LinearAccelerationSensorConstructor"/>
   <int value="2052" label="ReportUriMultipleEndpoints"/>
   <int value="2053" label="ReportUriSingleEndpoint"/>
+  <int value="2054" label="V8ConstructorNonUndefinedPrimitiveReturn"/>
+  <int value="2055"
+      label="EncryptedMediaDisallowedByFeaturePolicyInCrossOriginIframe"/>
+  <int value="2056"
+      label="GeolocationDisallowedByFeaturePolicyInCrossOriginIframe"/>
+  <int value="2057"
+      label="GetUserMediaMicDisallowedByFeaturePolicyInCrossOriginIframe"/>
+  <int value="2058"
+      label="GetUserMediaCameraDisallowedByFeaturePolicyInCrossOriginIframe"/>
+  <int value="2059"
+      label="RequestMIDIAccessDisallowedByFeaturePolicyInCrossOriginIframe"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -19543,6 +19554,8 @@
   <int value="16" label="GSA account doesn't match Chrome's"/>
   <int value="17" label="GMS call result status is null"/>
   <int value="18" label="GMS call result status is not successful"/>
+  <int value="19" label="Success with selection"/>
+  <int value="20" label="Duplicate entry"/>
 </enum>
 
 <enum name="IDBContextForcedCloseReason">
@@ -22379,6 +22392,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 +22438,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"/>
@@ -22552,6 +22567,7 @@
   <int value="-1473668019" label="token-binding:disabled"/>
   <int value="-1473136627" label="enable-web-payments"/>
   <int value="-1469228683" label="QuickUnlockPinSignin:disabled"/>
+  <int value="-1468126425" label="ResourceLoadScheduler:disabled"/>
   <int value="-1467332609" label="tab-management-experiment-type-anise"/>
   <int value="-1466990325" label="CrosCompUpdates:enabled"/>
   <int value="-1463410070" label="IPH_DemoMode:enabled"/>
@@ -22861,6 +22877,7 @@
   <int value="-378033324" label="disable-win32k-renderer-lockdown"/>
   <int value="-374657496" label="OmniboxEnableClipboardProvider:enabled"/>
   <int value="-365920680" label="ImageCaptureAPI:disabled"/>
+  <int value="-364587218" label="ResourceLoadScheduler:enabled"/>
   <int value="-364325011" label="enable-files-quick-view"/>
   <int value="-364267715" label="disable-native-cups"/>
   <int value="-362022976" label="disable-quirks-client"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ccb12be..5e92fef5 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>
@@ -83396,6 +83414,9 @@
 
 <histogram name="WebApk.Install.GooglePlayInstallState"
     enum="WebApkGooglePlayInstallState">
+  <obsolete>
+    Deleted in M61.
+  </obsolete>
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -87841,6 +87862,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/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 3994165..d9cb199 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -489,55 +489,6 @@
   <metric name="AudioVideo.SRC"/>
 </event>
 
-<event name="Memory.Experimental">
-  <owner>erikchen@chromium.org</owner>
-  <summary>
-    Metrics associated with memory consumption, in MB.
-  </summary>
-  <metric name="BlinkGC">
-    <summary>
-      Measure of memory consumed by Oilpan.
-    </summary>
-  </metric>
-  <metric name="CommandBuffer">
-    <summary>
-      Measure of memory consumed by GL command buffer.
-    </summary>
-  </metric>
-  <metric name="Malloc">
-    <summary>
-      Measure of memory allocated by malloc.
-    </summary>
-  </metric>
-  <metric name="PartitionAlloc">
-    <summary>
-      Measure of memory allocated by PartitionAlloc.
-    </summary>
-  </metric>
-  <metric name="PrivateMemoryFootprint">
-    <summary>
-      Measure of total memory consumed by process.
-    </summary>
-  </metric>
-  <metric name="ProcessType">
-    <summary>
-      Type of process (e.g. browser, renderer, GPU --- see
-      services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom)
-      of associated metrics.
-    </summary>
-  </metric>
-  <metric name="Resident">
-    <summary>
-      Size of process' working set.
-    </summary>
-  </metric>
-  <metric name="V8">
-    <summary>
-      Measure of memory consumed by V8.
-    </summary>
-  </metric>
-</event>
-
 <event name="PageDomainInfo">
   <owner>uthakore@chromium.org</owner>
   <summary>
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 0d7d03c6..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/base/BUILD.gn b/ui/base/BUILD.gn
index f7b9f78..63ec3df 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -377,6 +377,14 @@
     sources -= [ "touch/touch_device_util.cc" ]
   }
 
+  if (is_fuchsia) {
+    sources += [
+      "clipboard/clipboard_fuchsia.cc",
+      "clipboard/clipboard_fuchsia.h",
+      "resource/resource_bundle_fuchsia.cc",
+    ]
+  }
+
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index dd18ad5..8d0cd38 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -70,7 +70,7 @@
 
 #if defined(OS_WIN)
     const FORMATETC& ToFormatEtc() const { return data_; }
-#elif defined(USE_AURA) || defined(OS_ANDROID)
+#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
     const std::string& ToString() const { return data_; }
 #elif defined(OS_MACOSX)
     NSString* ToNSString() const { return data_; }
@@ -96,7 +96,7 @@
     explicit FormatType(UINT native_format);
     FormatType(UINT native_format, LONG index);
     FORMATETC data_;
-#elif defined(USE_AURA) || defined(OS_ANDROID)
+#elif defined(USE_AURA) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
     explicit FormatType(const std::string& native_format);
     std::string data_;
 #elif defined(OS_MACOSX)
diff --git a/ui/base/clipboard/clipboard_fuchsia.cc b/ui/base/clipboard/clipboard_fuchsia.cc
new file mode 100644
index 0000000..72de3f4
--- /dev/null
+++ b/ui/base/clipboard/clipboard_fuchsia.cc
@@ -0,0 +1,281 @@
+// 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 "ui/base/clipboard/clipboard_fuchsia.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+const char kMimeTypeBitmap[] = "image/bmp";
+
+// Clipboard::FormatType implementation.
+Clipboard::FormatType::FormatType() {}
+
+Clipboard::FormatType::FormatType(const std::string& native_format)
+    : data_(native_format) {}
+
+Clipboard::FormatType::~FormatType() {}
+
+std::string Clipboard::FormatType::Serialize() const {
+  return data_;
+}
+
+// static
+Clipboard::FormatType Clipboard::FormatType::Deserialize(
+    const std::string& serialization) {
+  return FormatType(serialization);
+}
+
+bool Clipboard::FormatType::operator<(const FormatType& other) const {
+  return data_ < other.data_;
+}
+
+bool Clipboard::FormatType::Equals(const FormatType& other) const {
+  return data_ == other.data_;
+}
+
+// Various predefined FormatTypes.
+// static
+Clipboard::FormatType Clipboard::GetFormatType(
+    const std::string& format_string) {
+  return FormatType::Deserialize(format_string);
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
+  return GetUrlFormatType();
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
+  return GetPlainTextFormatType();
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
+  return type;
+}
+
+// static
+const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
+  return type;
+}
+
+// Clipboard factory method.
+// static
+Clipboard* Clipboard::Create() {
+  return new ClipboardFuchsia;
+}
+
+// ClipboardFuchsia implementation.
+
+ClipboardFuchsia::ClipboardFuchsia() {
+  DCHECK(CalledOnValidThread());
+}
+
+ClipboardFuchsia::~ClipboardFuchsia() {
+  DCHECK(CalledOnValidThread());
+}
+
+void ClipboardFuchsia::OnPreShutdown() {}
+
+uint64_t ClipboardFuchsia::GetSequenceNumber(ClipboardType type) const {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+bool ClipboardFuchsia::IsFormatAvailable(const Clipboard::FormatType& format,
+                                         ClipboardType type) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTIMPLEMENTED();
+  return false;
+}
+
+void ClipboardFuchsia::Clear(ClipboardType type) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::ReadAvailableTypes(ClipboardType type,
+                                          std::vector<base::string16>* types,
+                                          bool* contains_filenames) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTIMPLEMENTED();
+  types->clear();
+  *contains_filenames = false;
+}
+
+void ClipboardFuchsia::ReadText(ClipboardType type,
+                                base::string16* result) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTREACHED();
+}
+
+void ClipboardFuchsia::ReadAsciiText(ClipboardType type,
+                                     std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTREACHED();
+}
+
+// Note: |src_url| isn't really used. It is only implemented in Windows
+void ClipboardFuchsia::ReadHTML(ClipboardType type,
+                                base::string16* markup,
+                                std::string* src_url,
+                                uint32_t* fragment_start,
+                                uint32_t* fragment_end) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTREACHED();
+}
+
+void ClipboardFuchsia::ReadRTF(ClipboardType type, std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  NOTREACHED();
+}
+
+SkBitmap ClipboardFuchsia::ReadImage(ClipboardType type) const {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTREACHED();
+  return SkBitmap();
+}
+
+void ClipboardFuchsia::ReadCustomData(ClipboardType clipboard_type,
+                                      const base::string16& type,
+                                      base::string16* result) const {
+  DCHECK(CalledOnValidThread());
+  NOTREACHED();
+}
+
+void ClipboardFuchsia::ReadBookmark(base::string16* title,
+                                    std::string* url) const {
+  DCHECK(CalledOnValidThread());
+  NOTREACHED();
+}
+
+void ClipboardFuchsia::ReadData(const Clipboard::FormatType& format,
+                                std::string* result) const {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+  result->clear();
+}
+
+base::Time ClipboardFuchsia::GetLastModifiedTime() const {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+  return base::Time();
+}
+
+void ClipboardFuchsia::ClearLastModifiedTime() {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+// Main entry point used to write several values in the clipboard.
+void ClipboardFuchsia::WriteObjects(ClipboardType type,
+                                    const ObjectMap& objects) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteText(const char* text_data, size_t text_len) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteHTML(const char* markup_data,
+                                 size_t markup_len,
+                                 const char* url_data,
+                                 size_t url_len) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteRTF(const char* rtf_data, size_t data_len) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteBookmark(const char* title_data,
+                                     size_t title_len,
+                                     const char* url_data,
+                                     size_t url_len) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteWebSmartPaste() {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteBitmap(const SkBitmap& bitmap) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+void ClipboardFuchsia::WriteData(const Clipboard::FormatType& format,
+                                 const char* data_data,
+                                 size_t data_len) {
+  DCHECK(CalledOnValidThread());
+  NOTIMPLEMENTED();
+}
+
+}  // namespace ui
diff --git a/ui/base/clipboard/clipboard_fuchsia.h b/ui/base/clipboard/clipboard_fuchsia.h
new file mode 100644
index 0000000..ca68893a
--- /dev/null
+++ b/ui/base/clipboard/clipboard_fuchsia.h
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_FUCHSIA_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_FUCHSIA_H_
+
+#include "ui/base/clipboard/clipboard.h"
+
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace ui {
+
+// This is a stub implementation of Clipboard for Fuchsia.
+// TODO(fuchsia): Implement this class.
+class ClipboardFuchsia : public Clipboard {
+ private:
+  friend class Clipboard;
+
+  ClipboardFuchsia();
+  ~ClipboardFuchsia() override;
+
+  // Clipboard overrides:
+  void OnPreShutdown() override;
+  uint64_t GetSequenceNumber(ClipboardType type) const override;
+  bool IsFormatAvailable(const FormatType& format,
+                         ClipboardType type) const override;
+  void Clear(ClipboardType type) override;
+  void ReadAvailableTypes(ClipboardType type,
+                          std::vector<base::string16>* types,
+                          bool* contains_filenames) const override;
+  void ReadText(ClipboardType type, base::string16* result) const override;
+  void ReadAsciiText(ClipboardType type, std::string* result) const override;
+  void ReadHTML(ClipboardType type,
+                base::string16* markup,
+                std::string* src_url,
+                uint32_t* fragment_start,
+                uint32_t* fragment_end) const override;
+  void ReadRTF(ClipboardType type, std::string* result) const override;
+  SkBitmap ReadImage(ClipboardType type) const override;
+  void ReadCustomData(ClipboardType clipboard_type,
+                      const base::string16& type,
+                      base::string16* result) const override;
+  void ReadBookmark(base::string16* title, std::string* url) const override;
+  void ReadData(const FormatType& format, std::string* result) const override;
+  base::Time GetLastModifiedTime() const override;
+  void ClearLastModifiedTime() override;
+  void WriteObjects(ClipboardType type, const ObjectMap& objects) override;
+  void WriteText(const char* text_data, size_t text_len) override;
+  void WriteHTML(const char* markup_data,
+                 size_t markup_len,
+                 const char* url_data,
+                 size_t url_len) override;
+  void WriteRTF(const char* rtf_data, size_t data_len) override;
+  void WriteBookmark(const char* title_data,
+                     size_t title_len,
+                     const char* url_data,
+                     size_t url_len) override;
+  void WriteWebSmartPaste() override;
+  void WriteBitmap(const SkBitmap& bitmap) override;
+  void WriteData(const FormatType& format,
+                 const char* data_data,
+                 size_t data_len) override;
+
+  DISALLOW_COPY_AND_ASSIGN(ClipboardFuchsia);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_CLIPBOARD_CLIPBOARD_FUCHSIA_H_
diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
index 7520145f..6baa87a 100644
--- a/ui/chromeos/touch_exploration_controller.cc
+++ b/ui/chromeos/touch_exploration_controller.cc
@@ -171,7 +171,7 @@
   // In order to avoid accidentally double tapping when moving off the edge
   // of the screen, the state will be rewritten to NoFingersDown.
   if ((type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) &&
-      FindEdgesWithinBounds(touch_event.location(), kLeavingScreenEdge) !=
+      FindEdgesWithinInset(touch_event.location(), kLeavingScreenEdge) !=
           NO_EDGE) {
     if (VLOG_on_)
       VLOG(1) << "Leaving screen";
@@ -272,11 +272,11 @@
   }
 
   // If the user enters the screen from the edge then send an earcon.
-  int edge = FindEdgesWithinBounds(event.location(), kLeavingScreenEdge);
+  int edge = FindEdgesWithinInset(event.location(), kLeavingScreenEdge);
   if (edge != NO_EDGE)
     delegate_->PlayEnterScreenEarcon();
 
-  int location = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
+  int location = FindEdgesWithinInset(event.location(), kSlopDistanceFromEdge);
   // If the press was at a corner, the user might go into corner passthrough
   // instead.
   bool in_a_bottom_corner =
@@ -301,7 +301,7 @@
     std::unique_ptr<ui::Event>* rewritten_event) {
   const ui::EventType type = event.type();
 
-  int location = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
+  int location = FindEdgesWithinInset(event.location(), kMaxDistanceFromEdge);
   bool in_a_bottom_corner =
       (location == BOTTOM_LEFT_CORNER) || (location == BOTTOM_RIGHT_CORNER);
   // If the event is from the initial press and the location is no longer in the
@@ -353,7 +353,7 @@
               << gesture_detector_config_.minimum_swipe_velocity;
     }
     // Change to slide gesture if the slide occurred at the right edge.
-    int edge = FindEdgesWithinBounds(event.location(), kMaxDistanceFromEdge);
+    int edge = FindEdgesWithinInset(event.location(), kMaxDistanceFromEdge);
     if (edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER) {
       SET_STATE(SLIDE_GESTURE);
       return InSlideGesture(event, rewritten_event);
@@ -516,7 +516,7 @@
 
   // If the first finger has left the corner, then exit passthrough.
   if (event.pointer_details().id == initial_press_->pointer_details().id) {
-    int edges = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
+    int edges = FindEdgesWithinInset(event.location(), kSlopDistanceFromEdge);
     bool in_a_bottom_corner = (edges == BOTTOM_LEFT_CORNER) ||
                               (edges == BOTTOM_RIGHT_CORNER);
     if (type == ui::ET_TOUCH_MOVED && in_a_bottom_corner)
@@ -704,7 +704,7 @@
 
   // Allows user to return to the edge to adjust the sound if they have left the
   // boundaries.
-  int edge = FindEdgesWithinBounds(event.location(), kSlopDistanceFromEdge);
+  int edge = FindEdgesWithinInset(event.location(), kSlopDistanceFromEdge);
   if (!(edge & RIGHT_EDGE) && (type != ui::ET_TOUCH_RELEASED)) {
     if (sound_timer_.IsRunning()) {
       sound_timer_.Stop();
@@ -842,7 +842,7 @@
 
   gfx::Point location =
       ToRoundedPoint(touch_locations_[initial_press_->pointer_details().id]);
-  int corner = FindEdgesWithinBounds(location, kSlopDistanceFromEdge);
+  int corner = FindEdgesWithinInset(location, kSlopDistanceFromEdge);
   if (corner != BOTTOM_LEFT_CORNER && corner != BOTTOM_RIGHT_CORNER)
     return;
 
@@ -905,7 +905,7 @@
   // their finger along the right side of the screen. Volume is relative to
   // where they are on the right side of the screen.
   gfx::Point location = gesture->location();
-  int edge = FindEdgesWithinBounds(location, kSlopDistanceFromEdge);
+  int edge = FindEdgesWithinInset(location, kSlopDistanceFromEdge);
   if (!(edge & RIGHT_EDGE))
     return;
 
@@ -1017,32 +1017,29 @@
 }
 
 gfx::Rect TouchExplorationController::GetRootWindowBoundsInScreenUnits() {
-  gfx::Point root_window_size = root_window_->bounds().bottom_right();
-  root_window_->GetHost()->ConvertDIPToScreenInPixels(&root_window_size);
+  gfx::Point root_window_size(root_window_->bounds().width(),
+                              root_window_->bounds().height());
+  root_window_->GetHost()->ConvertDIPToPixels(&root_window_size);
   return gfx::Rect(0, 0, root_window_size.x(), root_window_size.y());
 }
 
-int TouchExplorationController::FindEdgesWithinBounds(gfx::Point point,
-                                                      float bounds) {
-  gfx::Rect window = GetRootWindowBoundsInScreenUnits();
-
-  float left_edge_limit = window.x() + bounds;
-  float right_edge_limit = window.right() - bounds;
-  float top_edge_limit = window.y() + bounds;
-  float bottom_edge_limit = window.bottom() - bounds;
+int TouchExplorationController::FindEdgesWithinInset(gfx::Point point,
+                                                     float inset) {
+  gfx::RectF inner_bounds(GetRootWindowBoundsInScreenUnits());
+  inner_bounds.Inset(inset, inset);
 
   // Bitwise manipulation in order to determine where on the screen the point
   // lies. If more than one bit is turned on, then it is a corner where the two
   // bit/edges intersect. Otherwise, if no bits are turned on, the point must be
   // in the center of the screen.
   int result = NO_EDGE;
-  if (point.x() < left_edge_limit)
+  if (point.x() < inner_bounds.x())
     result |= LEFT_EDGE;
-  if (point.x() > right_edge_limit)
+  if (point.x() > inner_bounds.right())
     result |= RIGHT_EDGE;
-  if (point.y() < top_edge_limit)
+  if (point.y() < inner_bounds.y())
     result |= TOP_EDGE;
-  if (point.y() > bottom_edge_limit)
+  if (point.y() > inner_bounds.bottom())
     result |= BOTTOM_EDGE;
   return result;
 }
diff --git a/ui/chromeos/touch_exploration_controller.h b/ui/chromeos/touch_exploration_controller.h
index 6040682..5e895988 100644
--- a/ui/chromeos/touch_exploration_controller.h
+++ b/ui/chromeos/touch_exploration_controller.h
@@ -437,11 +437,11 @@
   // is not the same as screen coordinates, which span multiple displays.
   gfx::Rect GetRootWindowBoundsInScreenUnits();
 
-  // Given a point, if it is within the given bounds of an edge, returns the
-  // edge. If it is within the given bounds of two edges, returns an int with
+  // Given a point, if it is within the given inset of an edge, returns the
+  // edge. If it is within the given inset of two edges, returns an int with
   // both bits that represent the respective edges turned on. Otherwise returns
   // SCREEN_CENTER.
-  int FindEdgesWithinBounds(gfx::Point point, float bounds);
+  int FindEdgesWithinInset(gfx::Point point, float inset);
 
   // Set the state and modifies any variables related to the state change.
   // (e.g. resetting the gesture provider).
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/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 54f6bc7..fc7ae5c 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -13,18 +13,6 @@
     "file_manager_resources.pak",
     "file_manager_resources.rc",
   ]
-  if (enable_nacl) {
-    zip_archiver_pexe = "$root_gen_dir/ui/file_manager/zip_archiver_pnacl.pexe.js"
-    grit_flags = [
-      "-E",
-      "zip_archiver_pexe=" + rebase_path(zip_archiver_pexe, root_build_dir),
-      "-D",
-      "enable_nacl",
-    ]
-    deps = [
-      "//ui/file_manager/zip_archiver/:zip_archiver",
-    ]
-  }
 }
 
 component("file_manager") {
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index c002ef1..a9501b0 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -735,6 +735,28 @@
 };
 
 /**
+ * Compares two entry arrays.
+ * @param {Array<!Entry>} entries1 The entry array to be compared.
+ * @param {Array<!Entry>} entries2 The entry array to be compared.
+ * @return {boolean} True if the both arrays contain same files or directories
+ *     in the same order. Returns true if both arrays are null.
+ */
+util.isSameEntries = function(entries1, entries2) {
+  if (!entries1 && !entries2)
+    return true;
+  if (!entries1 || !entries2)
+    return false;
+  if (entries1.length !== entries2.length)
+    return false;
+  for (var i = 0; i < entries1.length; i++) {
+    if (!util.isSameEntry(entries1[i], entries2[i])) {
+      return false;
+    }
+  }
+  return true;
+};
+
+/**
  * Compares two file systems.
  * @param {FileSystem} fileSystem1 The file system to be compared.
  * @param {FileSystem} fileSystem2 The file system to be compared.
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index d40eb336..3fc916d 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -68,6 +68,15 @@
   this.defaultTask_ = defaultTask;
 };
 
+FileTasks.prototype = {
+  /**
+   * @return {!Array<!Entry>}
+   */
+  get entries() {
+    return this.entries_;
+  }
+};
+
 /**
  * The app ID of the video player app.
  * @const
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index 3a6dfba..4ea89434 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -98,13 +98,6 @@
    */
   this.pressingTab_ = false;
 
-  /**
-   * The last clicked item in the file list.
-   * @type {HTMLLIElement}
-   * @private
-   */
-  this.lastClickedItem_ = null;
-
   // Register events.
   ui.listContainer.element.addEventListener(
       'keydown', this.onListKeyDown_.bind(this));
@@ -113,9 +106,9 @@
   ui.listContainer.element.addEventListener(
       ListContainer.EventType.TEXT_SEARCH, this.onTextSearch_.bind(this));
   ui.listContainer.table.list.addEventListener(
-      'click', this.onDetailClick_.bind(this));
+      'dblclick', this.onDoubleClick_.bind(this));
   ui.listContainer.grid.addEventListener(
-      'click', this.onDetailClick_.bind(this));
+      'dblclick', this.onDoubleClick_.bind(this));
   ui.listContainer.table.list.addEventListener(
       'focus', this.onFileListFocus_.bind(this));
   ui.listContainer.grid.addEventListener(
@@ -159,12 +152,12 @@
 };
 
 /**
- * Handles mouse click or tap.
+ * Handles a double click event.
  *
- * @param {Event} event The click event.
+ * @param {Event} event The dblclick event.
  * @private
  */
-MainWindowComponent.prototype.onDetailClick_ = function(event) {
+MainWindowComponent.prototype.onDoubleClick_ = function(event) {
   if (this.namingController_.isRenamingInProgress()) {
     // Don't pay attention to clicks during a rename.
     return;
@@ -172,19 +165,13 @@
 
   var listItem = this.ui_.listContainer.findListItemForNode(
       event.touchedElement || event.srcElement);
+  // It is expected that the target item should have already been selected in
+  // LiseSelectionController.handlePointerDownUp on preceding mousedown event.
   var selection = this.selectionHandler_.selection;
   if (!listItem || !listItem.selected || selection.totalCount != 1) {
     return;
   }
 
-  // React on double click, but only if both clicks hit the same item.
-  // TODO(mtomasz): Simplify it, and use a double click handler if possible.
-  var clickNumber = (this.lastClickedItem_ == listItem) ? 2 : undefined;
-  this.lastClickedItem_ = listItem;
-
-  if (event.detail != clickNumber)
-    return;
-
   var entry = selection.entries[0];
   if (entry.isDirectory) {
     this.directoryModel_.changeDirectoryEntry(
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index a703d14c..dba35e62 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -90,6 +90,18 @@
    */
   this.tasks_ = null;
 
+  /**
+   * Entries that are used to generate FileTasks returned by this.tasks_.
+   * @private {!Array<!Entry>}
+   */
+  this.tasksEntries_ = [];
+
+  /**
+   * Selected entries from the last time onSelectionChanged_ was called.
+   * @private {!Array<!Entry>}
+   */
+  this.lastSelectedEntries_ = [];
+
   ui.taskMenuButton.addEventListener(
       'select', this.onTaskItemClicked_.bind(this));
   this.selectionHandler_.addEventListener(
@@ -262,20 +274,23 @@
  * @private
  */
 TaskController.prototype.onSelectionChanged_ = function() {
-  this.tasks_ = null;
   var selection = this.selectionHandler_.selection;
   // Caller of update context menu task items.
   // FileSelectionHandler.EventType.CHANGE
   if (this.dialogType_ === DialogType.FULL_PAGE &&
       (selection.directoryCount > 0 || selection.fileCount > 0)) {
-    // Show disabled items for position calculation of the menu. They will be
-    // overridden in this.updateFileSelectionAsync().
-    this.updateContextMenuTaskItems_(
-        [TaskController.createTemporaryDisabledTaskItem_()]);
+    // Compare entries while ignoring changes inside directories.
+    if (!util.isSameEntries(this.lastSelectedEntries_, selection.entries)) {
+      // Show disabled items for position calculation of the menu. They will be
+      // overridden in this.updateTasks_().
+      this.updateContextMenuTaskItems_(
+          [TaskController.createTemporaryDisabledTaskItem_()]);
+    }
   } else {
     // Update context menu.
     this.updateContextMenuTaskItems_([]);
   }
+  this.lastSelectedEntries_ = selection.entries;
 };
 
 /**
@@ -298,30 +313,38 @@
   } else {
     this.ui_.taskMenuButton.hidden = true;
   }
-}
+};
 
 /**
  * @return {!Promise<!FileTasks>}
  * @public
  */
 TaskController.prototype.getFileTasks = function() {
-  if (this.tasks_)
-    return this.tasks_;
-
   var selection = this.selectionHandler_.selection;
-  return selection.computeAdditional(this.metadataModel_).then(
-      function() {
-        if (this.selectionHandler_.selection !== selection)
+  if (this.tasks_ && util.isSameEntries(this.tasksEntries_, selection.entries))
+    return this.tasks_;
+  this.tasksEntries_ = selection.entries;
+  this.tasks_ =
+      selection.computeAdditional(this.metadataModel_).then(function() {
+        if (this.selectionHandler_.selection !== selection) {
+          if (util.isSameEntries(this.tasksEntries_, selection.entries))
+            this.tasks_ = null;
           return Promise.reject();
-        return FileTasks.create(
-            this.volumeManager_, this.metadataModel_, this.directoryModel_,
-            this.ui_, selection.entries, assert(selection.mimeTypes)).
-            then(function(tasks) {
-              if (this.selectionHandler_.selection !== selection)
+        }
+        return FileTasks
+            .create(
+                this.volumeManager_, this.metadataModel_, this.directoryModel_,
+                this.ui_, selection.entries, assert(selection.mimeTypes))
+            .then(function(tasks) {
+              if (this.selectionHandler_.selection !== selection) {
+                if (util.isSameEntries(this.tasksEntries_, selection.entries))
+                  this.tasks_ = null;
                 return Promise.reject();
+              }
               return tasks;
             }.bind(this));
       }.bind(this));
+  return this.tasks_;
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
index 34abed0..bd2d0f3 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
@@ -73,3 +73,157 @@
     assertEquals("handler-extension-id|file|play", info);
   }), callback);
 }
+
+function MockFileSelectionHandler() {
+  this.computeAdditionalCallback = function() {};
+  this.updateSelection([], []);
+}
+
+MockFileSelectionHandler.prototype.__proto__ = cr.EventTarget.prototype;
+
+MockFileSelectionHandler.prototype.updateSelection = function(
+    entries, mimeTypes) {
+  this.selection = {
+    entries: entries,
+    mimeTypes: mimeTypes,
+    computeAdditional: function(metadataModel) {
+      this.computeAdditionalCallback();
+      return new Promise(function(fulfill) {
+        fulfill();
+      });
+    }.bind(this)
+  };
+};
+
+function setupFileManagerPrivate() {
+  window.chrome.fileManagerPrivate = {
+    getFileTaskCalledCount_: 0,
+    getFileTasks: function(entries, callback) {
+      window.chrome.fileManagerPrivate.getFileTaskCalledCount_++;
+      setTimeout(
+          callback.bind(
+              null,
+              [
+                {taskId: 'handler-extension-id|file|open', isDefault: false},
+                {taskId: 'handler-extension-id|file|play', isDefault: true}
+              ]),
+          0);
+    },
+    onAppsUpdated: {
+      addListener: function() {},
+    },
+  };
+}
+
+function createTaskController(selectionHandler) {
+  return new TaskController(
+      DialogType.FULL_PAGE, {}, {
+        taskMenuButton: document.createElement('button'),
+        fileContextMenu:
+            {defaultActionMenuItem: document.createElement('div')}
+      },
+      new MockMetadataModel({}), {}, selectionHandler, null);
+}
+
+// TaskController.getFileTasks should not call fileManagerPrivate.getFileTasks
+// multiple times when the selected entries are not changed.
+function testGetFileTasksShouldNotBeCalledMultipleTimes(callback) {
+  setupFileManagerPrivate();
+  var selectionHandler = new MockFileSelectionHandler();
+  var fileSystem = new MockFileSystem('volumeId');
+  selectionHandler.updateSelection(
+      [new MockFileEntry(fileSystem, '/test.png', {})], ['image/png']);
+
+  var controller = createTaskController(selectionHandler);
+
+  assert(window.chrome.fileManagerPrivate.getFileTaskCalledCount_ === 0);
+  controller.getFileTasks()
+      .then(function(tasks) {
+        assert(window.chrome.fileManagerPrivate.getFileTaskCalledCount_ === 1);
+        assert(util.isSameEntries(
+            tasks.entries, selectionHandler.selection.entries));
+        // Make oldSelection.entries !== newSelection.entries
+        selectionHandler.updateSelection(
+            [new MockFileEntry(fileSystem, '/test.png', {})], ['image/png']);
+        return controller.getFileTasks();
+      })
+      .then(function(tasks) {
+        assert(window.chrome.fileManagerPrivate.getFileTaskCalledCount_ === 1);
+        assert(util.isSameEntries(
+            tasks.entries, selectionHandler.selection.entries));
+        callback();
+      })
+      .catch(function(error) {
+        assertNotReached(error);
+        callback();
+      });
+}
+
+// TaskController.getFileTasks should always return the promise whose FileTasks
+// corresponds to FileSelectionHandler.selection at the time
+// TaskController.getFileTasks is called.
+function testGetFileTasksShouldNotReturnObsoletePromise(callback) {
+  setupFileManagerPrivate();
+  var selectionHandler = new MockFileSelectionHandler();
+  var fileSystem = new MockFileSystem('volumeId');
+  selectionHandler.updateSelection(
+      [new MockFileEntry(fileSystem, '/test.png', {})], ['image/png']);
+
+  var controller = createTaskController(selectionHandler);
+  controller.getFileTasks()
+      .then(function(tasks) {
+        assert(util.isSameEntries(
+            tasks.entries, selectionHandler.selection.entries));
+
+        selectionHandler.updateSelection(
+            [new MockFileEntry(fileSystem, '/testtest.jpg', {})],
+            ['image/jpeg']);
+
+        return controller.getFileTasks();
+      })
+      .then(function(tasks) {
+        assert(util.isSameEntries(
+            tasks.entries, selectionHandler.selection.entries));
+        callback();
+      })
+      .catch(function(error) {
+        assertNotReached(error);
+        callback();
+      });
+}
+
+function testGetFileTasksShouldNotCacheRejectedPromise(callback) {
+  setupFileManagerPrivate();
+  var selectionHandler = new MockFileSelectionHandler();
+  var fileSystem = new MockFileSystem('volumeId');
+  selectionHandler.updateSelection(
+      [new MockFileEntry(fileSystem, '/test.png', {})], ['image/png']);
+
+  var controller = createTaskController(selectionHandler);
+
+  // Change FileSelection during getFileTasks call,
+  // so that the promise will be rejected.
+  selectionHandler.computeAdditionalCallback = function() {
+    selectionHandler.updateSelection(
+        [new MockFileEntry(fileSystem, '/test.png', {})], ['image/png']);
+  };
+
+  controller.getFileTasks().then(
+      function(tasks) {
+        assertNotReached('promise is not rejected');
+        callback();
+      },
+      function() {
+        selectionHandler.computeAdditionalCallback = function() {};
+        controller.getFileTasks().then(
+            function(tasks) {
+              assert(util.isSameEntries(
+                  tasks.entries, selectionHandler.selection.entries));
+              callback();
+            },
+            function() {
+              assertNotReached('promise is rejected');
+              callback();
+            });
+      });
+}
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index 82049626..4155d5ee 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -181,36 +181,6 @@
       <include name="IDR_GALLERY_BACKGROUND_JS" file="gallery/js/background_scripts.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_GALLERY_METADATA_WORKER_JS" file="gallery/js/metadata_worker.js" flattenhtml="true" type="BINDATA" />
 
-      <!-- Zip Archiver. -->
-      <include name="IDR_ZIP_ARCHIVER_MANIFEST" file="zip_archiver/manifest.json" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_COMPRESSOR_HTML" file="zip_archiver/html/compressor.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_DIALOG_HTML" file="zip_archiver/html/passphrase-dialog.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_HTML" file="zip_archiver/html/passphrase.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_POLYMER_HTML" flattenhtml="true" file="zip_archiver/third-party/polymer.html" allowexternalscript="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_APP_JS" file="zip_archiver/js/app.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_BACKGROUND_JS" file="zip_archiver/js/background.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_BUILD_CONFIG_JS" file="zip_archiver/js/build-config.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_COMPRESSOR_FOREGROUND_JS" file="zip_archiver/js/compressor-foreground.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_COMPRESSOR_JS" file="zip_archiver/js/compressor.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_DECOMPRESSOR_JS" file="zip_archiver/js/decompressor.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_DIALOG_JS" file="zip_archiver/js/passphrase-dialog.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_MANAGER_JS" file="zip_archiver/js/passphrase-manager.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_REQUEST_JS" file="zip_archiver/js/request.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_TYPES_JS" file="zip_archiver/js/types.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_UNPACKER_JS" file="zip_archiver/js/unpacker.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_VOLUME_JS" file="zip_archiver/js/volume.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_CSS" file="zip_archiver/css/passphrase.css" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_PASSPHRASE_DIALOG_CSS" file="zip_archiver/css/passphrase-dialog.css" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_ICON_16" file="zip_archiver/icons/icon16.png" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_ICON_32" file="zip_archiver/icons/icon32.png" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_ICON_64" file="zip_archiver/icons/icon64.png" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_ICON_96" file="zip_archiver/icons/icon96.png" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_ICON_128" file="zip_archiver/icons/icon128.png" type="BINDATA" />
-      <include name="IDR_ZIP_ARCHIVER_MODULE_NMF" file="zip_archiver/module.nmf.txt" type="BINDATA" />
-      <if expr="enable_nacl">
-        <include name="IDR_ZIP_ARCHIVER_PEXE" file="${zip_archiver_pexe}" use_base_dir="false" type="BINDATA" />
-      </if>
-
       <!-- Custom cursors (which grit cannot inline). -->
       <include name="IDR_FILE_MANAGER_IMG_GALLERY_CURSOR_CROP" file="gallery/images/100/cursor_crop.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_IMG_GALLERY_2X_CURSOR_CROP" file="gallery/images/200/cursor_crop.png" type="BINDATA" />
diff --git a/ui/file_manager/zip_archiver/BUILD.gn b/ui/file_manager/zip_archiver/BUILD.gn
deleted file mode 100644
index a0bc6de..0000000
--- a/ui/file_manager/zip_archiver/BUILD.gn
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/features.gni")
-
-copy("zip_archiver") {
-  pexe_dir = get_label_info(
-      "//ui/file_manager/zip_archiver/zip_archiver/cpp:zip_archiver_pnacl(//build/toolchain/nacl:newlib_pnacl)",
-      "root_out_dir")
-
-  sources = [
-    "$pexe_dir/zip_archiver_pnacl.pexe",
-  ]
-
-  outputs = [
-    "$root_gen_dir/ui/file_manager/{{source_file_part}}.js",
-  ]
-
-  deps = [
-    "//ui/file_manager/zip_archiver/cpp:zip_archiver_pnacl(//build/toolchain/nacl:newlib_pnacl)",
-  ]
-}
diff --git a/ui/file_manager/zip_archiver/check_js_for_errors.sh b/ui/file_manager/zip_archiver/check_js_for_errors.sh
deleted file mode 100755
index c7d71b6..0000000
--- a/ui/file_manager/zip_archiver/check_js_for_errors.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-NPM_ROOT=$(npm root)
-CLOSURE_DIR="${NPM_ROOT}/google-closure-compiler"
-PATH_TO_COMPILER="${CLOSURE_DIR}/compiler.jar"
-PATH_TO_EXTERNS_CHROME="${CLOSURE_DIR}/contrib/externs/chrome_extensions.js"
-
-java -jar $PATH_TO_COMPILER \
-  --checks-only --language_in=ECMASCRIPT6 --warning_level=VERBOSE \
-  --externs=externs_js/polymer.js --externs=$PATH_TO_EXTERNS_CHROME \
-  --externs=externs_js/chrome.js \
-  js/unpacker.js js/*.js
diff --git a/ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.h b/ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.h
deleted file mode 100644
index 41b36e6..0000000
--- a/ui/file_manager/zip_archiver/cpp/compressor_archive_minizip.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPRESSOR_ARCHIVE_MINIZIP_H_
-#define COMPRESSOR_ARCHIVE_MINIZIP_H_
-
-#include <string>
-
-#include "third_party/zlib/contrib/minizip/unzip.h"
-#include "third_party/zlib/contrib/minizip/zip.h"
-
-#include "compressor_archive.h"
-#include "compressor_stream.h"
-
-// A namespace with constants used by CompressorArchiveMinizip.
-namespace compressor_archive_constants {
-
-const char kCreateArchiveError[] = "Failed to create archive.";
-const char kAddToArchiveError[] = "Failed to add entry to archive.";
-const char kCloseArchiveError[] = "Failed to close archive.";
-
-}
-
-// A name space with custom functions passed to minizip.
-namespace compressor_archive_functions {
-
-  uLong CustomArchiveWrite(void* compressor,
-                           void* stream,
-                           const void* buffer,
-                           uLong length);
-
-  long CustomArchiveTell(void* compressor, void* stream);
-
-  long CustomArchiveSeek(void* compressor,
-                         void* stream,
-                         uLong offset,
-                         int origin);
-
-}  // compressor_archive_functions
-
-class CompressorArchiveMinizip : public CompressorArchive {
- public:
-  explicit CompressorArchiveMinizip(CompressorStream* compressor_stream);
-
-  virtual ~CompressorArchiveMinizip();
-
-  // Creates an archive object.
-  virtual bool CreateArchive();
-
-  // Releases all resources obtained by minizip.
-  virtual bool CloseArchive(bool has_error);
-
-  // Adds an entry to the archive.
-  virtual bool AddToArchive(const std::string& filename,
-                            int64_t file_size,
-                            int64_t modification_time,
-                            bool is_directory);
-
-  // A getter function for zip_file_.
-  zipFile zip_file() const { return zip_file_; }
-
-  // A getter function for compressor_stream.
-  CompressorStream* compressor_stream() const { return compressor_stream_; }
-
-  // Custom functions need to access private variables of
-  // CompressorArchiveMinizip frequently.
-  friend uLong compressor_archive_functions::CustomArchiveWrite(
-      void* compressor, void* stream, const void* buffer, uLong length);
-
-  friend long compressor_archive_functions::CustomArchiveTell(
-      void* compressor, void* stream);
-
-  friend long compressor_archive_functions::CustomArchiveSeek(
-      void* compressor, void* stream, uLong offset, int origin);
-
- private:
-  // An instance that takes care of all IO operations.
-  CompressorStream* compressor_stream_;
-
-  // The minizip correspondent archive object.
-  zipFile zip_file_;
-
-  // The buffer used to store the data read from JavaScript.
-  char* destination_buffer_;
-
-  // The current offset of the zip archive file.
-  int64_t offset_;
-  // The size of the zip archive file.
-  int64_t length_;
-};
-
-#endif  // COMPRESSOR_ARCHIVE_MINIZIP_H_
diff --git a/ui/file_manager/zip_archiver/css/passphrase.css b/ui/file_manager/zip_archiver/css/passphrase.css
deleted file mode 100644
index cdfb743..0000000
--- a/ui/file_manager/zip_archiver/css/passphrase.css
+++ /dev/null
@@ -1,13 +0,0 @@
-body {
-  -webkit-app-region: drag;
-  bottom: 0;
-  left: 0;
-  padding: 15px 15px 8px 15px;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
-#passphrase-dialog {
-  height: 100%;
-}
diff --git a/ui/file_manager/zip_archiver/js/compressor-foreground.js b/ui/file_manager/zip_archiver/js/compressor-foreground.js
deleted file mode 100644
index 661534c7..0000000
--- a/ui/file_manager/zip_archiver/js/compressor-foreground.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-window.onload = function() {
-  chrome.runtime.getBackgroundPage(function(backgroundPage) {
-
-    // Called from the background page. We need to place this function here
-    // because chrome.fileSystem.chooseEntry only works on forground page.
-    backgroundPage.unpacker.Compressor.prototype.createArchiveFileForeground_ =
-        function(compressorId) {
-          var compressor =
-              backgroundPage.unpacker.app.compressors[compressorId];
-          var suggestedName = compressor.archiveName_;
-          // Create an archive file.
-          chrome.fileSystem.chooseEntry(
-              {type: 'saveFile', suggestedName: suggestedName},
-              function(entry, fileEntries) {
-                if (!entry) {
-                  console.error('Failed to create an archive file.');
-                  compressor.onError_(compressor.compressorId_);
-                  return;
-                }
-
-                compressor.archiveFileEntry_ = entry;
-
-                compressor.sendCreateArchiveRequest_();
-              });
-        };
-
-    // Some compressors are waiting for this foreground page to be loaded.
-    backgroundPage.unpacker.Compressor.CompressorIdQueue.forEach(
-        function(compressorId) {
-          var compressor =
-              backgroundPage.unpacker.app.compressors[compressorId];
-          compressor.createArchiveFileForeground_(compressorId);
-        });
-  });
-};
diff --git a/ui/file_manager/zip_archiver/third-party/polymer.html b/ui/file_manager/zip_archiver/third-party/polymer.html
deleted file mode 100644
index b37ed2e..0000000
--- a/ui/file_manager/zip_archiver/third-party/polymer.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<link rel="import" href="../../third-party/polymer/bower_components/paper-button/paper-button.html">
-<link rel="import" href="../../third-party/polymer/bower_components/paper-input/paper-input.html">
-<link rel="import" href="../../third-party/polymer/bower_components/paper-checkbox/paper-checkbox.html">
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/passphrase_manager_test.js b/ui/file_manager/zip_archiver/unpacker-test/js/passphrase_manager_test.js
deleted file mode 100644
index 78f4c1d5..0000000
--- a/ui/file_manager/zip_archiver/unpacker-test/js/passphrase_manager_test.js
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-'use strict';
-
-describe('PassphraseManager', function() {
-  var passphraseWindow = null;
-  var passphraseWindowLoadCallback = null;
-
-  beforeEach(function() {
-    // This API is not available in Karma unit tests, so stub it using
-    // window.open.
-    chrome.app.window = {
-      create: function(url, options, callback) {
-        var closeCallbacks = [];
-        passphraseWindow = window.open(url);
-        passphraseWindow.onload = function() {
-          passphraseWindow.onEverythingLoaded = function() {
-            if (passphraseWindowLoadCallback)
-              passphraseWindowLoadCallback();
-          };
-          passphraseWindow.onunload = function() {
-            closeCallbacks.forEach(function(callback) {
-              callback();
-            });
-          };
-        };
-        callback({
-          contentWindow: passphraseWindow,
-          onClosed: {
-            addListener: function(onClosedCallback) {
-              closeCallbacks.push(onClosedCallback);
-            }
-          }
-        });
-      }
-    };
-  });
-
-  describe('that has an initial passphrase', function() {
-    var TEST_PASSPHRASE = 'hello-world';
-    var passphraseManager = new unpacker.PassphraseManager(TEST_PASSPHRASE);
-
-    afterEach(function() {
-      passphraseWindowLoadCallback = null;
-      if (passphraseWindow)
-        passphraseWindow.close();
-      passphraseWindow = null;
-    });
-
-    it('should return it immediately', function(done) {
-      passphraseManager.getPassphrase().then(function(passphrase) {
-        expect(passphrase).to.equal(TEST_PASSPHRASE);
-        expect(passphraseManager.rememberedPassphrase).to.equal(
-            TEST_PASSPHRASE);
-        done();
-      }).catch(test_utils.forceFailure);
-    });
-
-    it('should not return it again for the second call', function(done) {
-      passphraseWindowLoadCallback = function() {
-        // Close the window as soon as it's loaded.
-        passphraseWindow.close();
-      };
-      passphraseManager.getPassphrase().then(test_utils.forceFailure).
-          catch(function(error) {
-            expect(error).to.equal('FAILED');
-            done();
-          });
-    });
-  });
-
-  describe('without an initial passphrase', function() {
-    var USER_PASSPHRASE = 'hello-kitty';
-    var passphraseManager = new unpacker.PassphraseManager(null);
-
-    afterEach(function() {
-      passphraseWindowLoadCallback = null;
-      if (passphraseWindow)
-        passphraseWindow.close();
-      passphraseWindow = null;
-    });
-
-    it('should accept a passphrase from a user with remembering',
-        function(done) {
-          passphraseWindowLoadCallback = function() {
-            // Fill out the password field and close the dialog as soon as it's
-            // loaded.
-            passphraseWindow.document.querySelector(
-                'html /deep/ #input').value = USER_PASSPHRASE;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #remember').checked = true;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #acceptButton').click();
-          };
-          passphraseManager.getPassphrase().then(function(passphrase) {
-            expect(passphrase).to.equal(USER_PASSPHRASE);
-            expect(passphraseManager.rememberedPassphrase).to.equal(
-                USER_PASSPHRASE);
-            done();
-          }).catch(test_utils.forceFailure);
-        });
-
-    it('should accept a passphrase from a user without remembering',
-        function(done) {
-          passphraseWindowLoadCallback = function() {
-            // Fill out the password field and close the dialog as soon as it's
-            // loaded.
-            passphraseWindow.document.querySelector(
-                'html /deep/ #input').value = USER_PASSPHRASE;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #acceptButton').click();
-          };
-          passphraseManager.getPassphrase().then(function(passphrase) {
-            expect(passphrase).to.equal(USER_PASSPHRASE);
-            expect(passphraseManager.rememberedPassphrase).to.be.null;
-            done();
-          }).catch(test_utils.forceFailure);
-        });
-
-    it('should reject password on window cancel button',
-        function(done) {
-          passphraseWindowLoadCallback = function() {
-            passphraseWindow.document.querySelector(
-                'html /deep/ #input').value = USER_PASSPHRASE;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #remember').checked = true;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #cancelButton').click();
-          };
-          passphraseManager.getPassphrase().then(
-              test_utils.forceFailure,
-              function(error) {
-                expect(error).to.equal('FAILED');
-                expect(passphraseManager.rememberedPassphrase).to.be.null;
-                done();
-              });
-        });
-
-    it('should reject password on window close',
-        function(done) {
-          passphraseWindowLoadCallback = function() {
-            passphraseWindow.document.querySelector(
-                'html /deep/ #input').value = USER_PASSPHRASE;
-            passphraseWindow.document.querySelector(
-                'html /deep/ #remember').checked = true;
-            passphraseWindow.close();
-          };
-          passphraseManager.getPassphrase().then(
-              test_utils.forceFailure,
-              function(error) {
-                expect(error).to.equal('FAILED');
-                expect(passphraseManager.rememberedPassphrase).to.be.null;
-                done();
-              });
-        });
-  });
-});
diff --git a/ui/file_manager/zip_archiver/unpacker-test/js/request_test.js b/ui/file_manager/zip_archiver/unpacker-test/js/request_test.js
deleted file mode 100644
index 0e68985..0000000
--- a/ui/file_manager/zip_archiver/unpacker-test/js/request_test.js
+++ /dev/null
@@ -1,282 +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.
-
-'use strict';
-
-describe('On calling', function() {
-  /**
-   * @const {string}
-   */
-  var FILE_SYSTEM_ID = 'id';
-
-  /**
-   * @const {number}
-   */
-  var REQUEST_ID = 10;
-
-  /**
-   * @const {string}
-   */
-  var ENCODING = 'CP1250';
-
-  /**
-   * @const {number}
-   */
-  var ARCHIVE_SIZE = 5000;
-
-  /**
-   * @const {!ArrayBuffer}
-   */
-  var CHUNK_BUFFER = new ArrayBuffer(5);
-
-  /**
-   * @const {number}
-   */
-  var CHUNK_OFFSET = 150;
-
-  /**
-   * @const {string}
-   */
-  var CLOSE_VOLUME_REQUEST_ID = '-1';
-
-  /**
-   * @const {number}
-   */
-  var INDEX = 123;
-
-  /**
-   * @const {number}
-   */
-  var OPEN_REQUEST_ID = 7;
-
-  /**
-   * @const {number}
-   */
-  var OFFSET = 50;
-
-  /**
-   * @const {number}
-   */
-  var LENGTH = 200;
-
-  describe('request.createReadMetadataRequest should create a request',
-           function() {
-    var readMetadataRequest;
-    beforeEach(function() {
-      readMetadataRequest = unpacker.request.createReadMetadataRequest(
-          FILE_SYSTEM_ID, REQUEST_ID, ENCODING, ARCHIVE_SIZE);
-    });
-
-    it('with READ_METADATA as operation', function() {
-      expect(readMetadataRequest[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.READ_METADATA);
-    });
-
-    it('with correct file system id', function() {
-      expect(readMetadataRequest[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(readMetadataRequest[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-
-    it('with correct encoding', function() {
-      expect(readMetadataRequest[unpacker.request.Key.ENCODING])
-          .to.equal(ENCODING);
-    });
-
-    it('with correct archive size', function() {
-      expect(readMetadataRequest[unpacker.request.Key.ARCHIVE_SIZE])
-          .to.equal(ARCHIVE_SIZE.toString());
-    });
-  });
-
-  describe('request.createReadChunkDoneResponse should create a response',
-           function() {
-    var readChunkDoneReponse;
-    beforeEach(function() {
-      readChunkDoneReponse = unpacker.request.createReadChunkDoneResponse(
-          FILE_SYSTEM_ID, REQUEST_ID, CHUNK_BUFFER, CHUNK_OFFSET);
-    });
-
-    it('with READ_CHUNK_DONE as operation', function() {
-      expect(readChunkDoneReponse[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.READ_CHUNK_DONE);
-    });
-
-    it('with correct file system id', function() {
-      expect(readChunkDoneReponse[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(readChunkDoneReponse[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-
-    it('with correct chunk buffer', function() {
-      expect(readChunkDoneReponse[unpacker.request.Key.CHUNK_BUFFER])
-          .to.equal(CHUNK_BUFFER);
-    });
-
-    it('with correct chunk offset', function() {
-      expect(readChunkDoneReponse[unpacker.request.Key.OFFSET])
-          .to.equal(CHUNK_OFFSET.toString());
-    });
-  });
-
-  describe('request.createReadChunkErrorResponse should create a response',
-           function() {
-    var readChunkErrorReponse;
-    beforeEach(function() {
-      readChunkErrorReponse = unpacker.request.createReadChunkErrorResponse(
-          FILE_SYSTEM_ID, REQUEST_ID, CHUNK_BUFFER);
-    });
-
-    it('with READ_CHUNK_ERROR as operation', function() {
-      expect(readChunkErrorReponse[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.READ_CHUNK_ERROR);
-    });
-
-    it('with correct file system id', function() {
-      expect(readChunkErrorReponse[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(readChunkErrorReponse[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-  });
-
-  describe('request.createCloseVolumeRequest should create a request',
-           function() {
-    var closeVolumeRequest;
-    beforeEach(function() {
-      closeVolumeRequest =
-          unpacker.request.createCloseVolumeRequest(FILE_SYSTEM_ID);
-    });
-
-    it('with CLOSE_VOLUME as operation', function() {
-      expect(closeVolumeRequest[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.CLOSE_VOLUME);
-    });
-
-    it('with correct file system id', function() {
-      expect(closeVolumeRequest[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(closeVolumeRequest[unpacker.request.Key.REQUEST_ID])
-          .to.equal(CLOSE_VOLUME_REQUEST_ID);
-    });
-  });
-
-  describe('request.createOpenFileRequest should create a request', function() {
-    var openFileRequest;
-    beforeEach(function() {
-      openFileRequest = unpacker.request.createOpenFileRequest(
-          FILE_SYSTEM_ID, REQUEST_ID, INDEX, ENCODING, ARCHIVE_SIZE);
-    });
-
-    it('with OPEN_FILE as operation', function() {
-      expect(openFileRequest[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.OPEN_FILE);
-    });
-
-    it('with correct file system id', function() {
-      expect(openFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(openFileRequest[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-
-    it('with correct file path', function() {
-      expect(openFileRequest[unpacker.request.Key.INDEX])
-          .to.equal(INDEX.toString());
-    });
-
-    it('with correct encoding', function() {
-      expect(openFileRequest[unpacker.request.Key.ENCODING]).to.equal(ENCODING);
-    });
-
-    it('with correct archive size', function() {
-      expect(openFileRequest[unpacker.request.Key.ARCHIVE_SIZE])
-          .to.equal(ARCHIVE_SIZE.toString());
-    });
-  });
-
-  describe('request.createCloseFileRequest should create a request',
-      function() {
-    var closeFileRequest;
-    beforeEach(function() {
-      closeFileRequest = unpacker.request.createCloseFileRequest(
-          FILE_SYSTEM_ID, REQUEST_ID, OPEN_REQUEST_ID);
-    });
-
-    it('with CLOSE_FILE as operation', function() {
-      expect(closeFileRequest[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.CLOSE_FILE);
-    });
-
-    it('with correct file system id', function() {
-      expect(closeFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(closeFileRequest[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-
-    it('with correct open request id', function() {
-      expect(closeFileRequest[unpacker.request.Key.OPEN_REQUEST_ID])
-          .to.equal(OPEN_REQUEST_ID.toString());
-    });
-  });
-
-  describe('request.createReadFileRequest should create a request', function() {
-    var readFileRequest;
-    beforeEach(function() {
-      readFileRequest = unpacker.request.createReadFileRequest(
-          FILE_SYSTEM_ID, REQUEST_ID, OPEN_REQUEST_ID, OFFSET, LENGTH);
-    });
-
-    it('with READ_FILE as operation', function() {
-      expect(readFileRequest[unpacker.request.Key.OPERATION])
-          .to.equal(unpacker.request.Operation.READ_FILE);
-    });
-
-    it('with correct file system id', function() {
-      expect(readFileRequest[unpacker.request.Key.FILE_SYSTEM_ID])
-          .to.equal(FILE_SYSTEM_ID);
-    });
-
-    it('with correct request id', function() {
-      expect(readFileRequest[unpacker.request.Key.REQUEST_ID])
-          .to.equal(REQUEST_ID.toString());
-    });
-
-    it('with correct open request id', function() {
-      expect(readFileRequest[unpacker.request.Key.OPEN_REQUEST_ID])
-          .to.equal(OPEN_REQUEST_ID.toString());
-    });
-
-    it('with correct offset', function() {
-      expect(readFileRequest[unpacker.request.Key.OFFSET])
-          .to.equal(OFFSET.toString());
-    });
-
-    it('with correct length', function() {
-      expect(readFileRequest[unpacker.request.Key.LENGTH])
-          .to.equal(LENGTH.toString());
-    });
-  });
-});
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..606c345a 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/gfx/platform_font_linux.cc b/ui/gfx/platform_font_linux.cc
index 8c4a368..e6a81a06 100644
--- a/ui/gfx/platform_font_linux.cc
+++ b/ui/gfx/platform_font_linux.cc
@@ -43,7 +43,8 @@
 // updated to contain the fallback's family name.
 sk_sp<SkTypeface> CreateSkTypeface(bool italic,
                                    gfx::Font::Weight weight,
-                                   std::string* family) {
+                                   std::string* family,
+                                   bool* out_success) {
   DCHECK(family);
 
   const int font_weight = (weight == Font::Weight::INVALID)
@@ -59,10 +60,13 @@
     // scalable font.
     typeface = sk_sp<SkTypeface>(SkTypeface::MakeFromName(
         kFallbackFontFamilyName, sk_style));
-    CHECK(typeface) << "Could not find any font: " << *family << ", "
-                    << kFallbackFontFamilyName;
+    if (!typeface) {
+      *out_success = false;
+      return nullptr;
+    }
     *family = kFallbackFontFamilyName;
   }
+  *out_success = true;
   return typeface;
 }
 
@@ -76,42 +80,7 @@
 // PlatformFontLinux, public:
 
 PlatformFontLinux::PlatformFontLinux() {
-  if (!g_default_font.Get()) {
-    std::string family = kFallbackFontFamilyName;
-    int size_pixels = 12;
-    int style = Font::NORMAL;
-    Font::Weight weight = Font::Weight::NORMAL;
-    FontRenderParams params;
-
-#if defined(OS_CHROMEOS)
-    // On Chrome OS, a FontList font description string is stored as a
-    // translatable resource and passed in via SetDefaultFontDescription().
-    if (default_font_description_) {
-      FontRenderParamsQuery query;
-      CHECK(FontList::ParseDescription(*default_font_description_,
-                                       &query.families, &query.style,
-                                       &query.pixel_size, &query.weight))
-          << "Failed to parse font description " << *default_font_description_;
-      params = gfx::GetFontRenderParams(query, &family);
-      size_pixels = query.pixel_size;
-      style = query.style;
-      weight = query.weight;
-    }
-#else
-    // On Linux, LinuxFontDelegate is used to query the native toolkit (e.g.
-    // GTK+) for the default UI font.
-    const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
-    if (delegate) {
-      delegate->GetDefaultFontDescription(&family, &size_pixels, &style,
-                                          &weight, &params);
-    }
-#endif
-
-    g_default_font.Get() = new PlatformFontLinux(
-        CreateSkTypeface(style & Font::ITALIC, weight, &family), family,
-        size_pixels, style, weight, params);
-  }
-
+  CHECK(InitDefaultFont()) << "Could not find the default font";
   InitFromPlatformFont(g_default_font.Get().get());
 }
 
@@ -121,15 +90,59 @@
   query.families.push_back(font_name);
   query.pixel_size = font_size_pixels;
   query.weight = Font::Weight::NORMAL;
-  InitFromDetails(nullptr, font_name, font_size_pixels,
-                  Font::NORMAL, query.weight,
-                  gfx::GetFontRenderParams(query, NULL));
+  InitFromDetails(nullptr, font_name, font_size_pixels, Font::NORMAL,
+                  query.weight, gfx::GetFontRenderParams(query, nullptr));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // PlatformFontLinux, PlatformFont implementation:
 
 // static
+bool PlatformFontLinux::InitDefaultFont() {
+  if (g_default_font.Get())
+    return true;
+
+  bool success = false;
+  std::string family = kFallbackFontFamilyName;
+  int size_pixels = 12;
+  int style = Font::NORMAL;
+  Font::Weight weight = Font::Weight::NORMAL;
+  FontRenderParams params;
+
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, a FontList font description string is stored as a
+  // translatable resource and passed in via SetDefaultFontDescription().
+  if (default_font_description_) {
+    FontRenderParamsQuery query;
+    CHECK(FontList::ParseDescription(*default_font_description_,
+                                     &query.families, &query.style,
+                                     &query.pixel_size, &query.weight))
+        << "Failed to parse font description " << *default_font_description_;
+    params = gfx::GetFontRenderParams(query, &family);
+    size_pixels = query.pixel_size;
+    style = query.style;
+    weight = query.weight;
+  }
+#else
+  // On Linux, LinuxFontDelegate is used to query the native toolkit (e.g.
+  // GTK+) for the default UI font.
+  const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
+  if (delegate) {
+    delegate->GetDefaultFontDescription(&family, &size_pixels, &style, &weight,
+                                        &params);
+  }
+#endif
+
+  sk_sp<SkTypeface> typeface =
+      CreateSkTypeface(style & Font::ITALIC, weight, &family, &success);
+  if (!success)
+    return false;
+  g_default_font.Get() = new PlatformFontLinux(
+      std::move(typeface), family, size_pixels, style, weight, params);
+  return true;
+}
+
+// static
 void PlatformFontLinux::ReloadDefaultFont() {
   // Reset the scoped_refptr.
   g_default_font.Get() = nullptr;
@@ -153,10 +166,13 @@
 
   // If the style changed, we may need to load a new face.
   std::string new_family = font_family_;
+  bool success = true;
   sk_sp<SkTypeface> typeface =
       (weight == weight_ && style == style_)
           ? typeface_
-          : CreateSkTypeface(style, weight, &new_family);
+          : CreateSkTypeface(style, weight, &new_family, &success);
+  CHECK(success) << "Could not find any font: " << new_family << ", "
+                 << kFallbackFontFamilyName;
 
   FontRenderParamsQuery query;
   query.families.push_back(new_family);
@@ -249,8 +265,12 @@
   DCHECK_GT(font_size_pixels, 0);
 
   font_family_ = font_family;
-  typeface_ = typeface ? std::move(typeface) :
-      CreateSkTypeface(style & Font::ITALIC, weight, &font_family_);
+  bool success = true;
+  typeface_ = typeface ? std::move(typeface)
+                       : CreateSkTypeface(style & Font::ITALIC, weight,
+                                          &font_family_, &success);
+  CHECK(success) << "Could not find any font: " << font_family_ << ", "
+                 << kFallbackFontFamilyName;
 
   font_size_pixels_ = font_size_pixels;
   style_ = style;
diff --git a/ui/gfx/platform_font_linux.h b/ui/gfx/platform_font_linux.h
index a6f6e41..3dfd76c 100644
--- a/ui/gfx/platform_font_linux.h
+++ b/ui/gfx/platform_font_linux.h
@@ -25,6 +25,11 @@
   PlatformFontLinux();
   PlatformFontLinux(const std::string& font_name, int font_size_pixels);
 
+  // Initials the default PlatformFont. Returns true if this is successful, or
+  // false if fonts resources are not available. If this returns false, the
+  // calling service should shut down.
+  static bool InitDefaultFont();
+
   // Resets and reloads the cached system font used by the default constructor.
   // This function is useful when the system font has changed, for example, when
   // the locale has changed.
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/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 05bb656..3951c2a4 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -125,6 +125,10 @@
           //     .VirtualKeyboardOnTouchableDisplayOnly.
           {keyboard::KeyboardControllerState::LOADING_EXTENSION,
            keyboard::KeyboardControllerState::LOADING_EXTENSION},
+
+          // LOADING_EXTENSION -> HIDDEN occurs when the extension is pre-loaded
+          {keyboard::KeyboardControllerState::LOADING_EXTENSION,
+           keyboard::KeyboardControllerState::HIDDEN},
       };
   return kAllowedStateTransition.count(std::make_pair(from, to)) == 1;
 };
@@ -270,9 +274,9 @@
 // static
 KeyboardController* KeyboardController::instance_ = NULL;
 
-KeyboardController::KeyboardController(KeyboardUI* ui,
+KeyboardController::KeyboardController(std::unique_ptr<KeyboardUI> ui,
                                        KeyboardLayoutDelegate* delegate)
-    : ui_(ui),
+    : ui_(std::move(ui)),
       layout_delegate_(delegate),
       keyboard_visible_(false),
       show_on_resize_(false),
@@ -280,7 +284,6 @@
       keyboard_mode_(FULL_WIDTH),
       state_(KeyboardControllerState::UNKNOWN),
       weak_factory_(this) {
-  CHECK(ui);
   ui_->GetInputMethod()->AddObserver(this);
   ui_->SetController(this);
   ChangeState(KeyboardControllerState::INITIAL);
@@ -343,6 +346,13 @@
   }
 }
 
+void KeyboardController::NotifyKeyboardLoadingComplete() {
+  if (state_ != KeyboardControllerState::LOADING_EXTENSION)
+    return;
+
+  ChangeState(KeyboardControllerState::HIDDEN);
+}
+
 void KeyboardController::HideKeyboard(HideReason reason) {
   TRACE_EVENT0("vk", "HideKeyboard");
 
@@ -546,16 +556,32 @@
     ShowKeyboardInternal(display::kInvalidDisplayId);
 }
 
-void KeyboardController::ShowKeyboardInternal(int64_t display_id) {
+void KeyboardController::LoadKeyboardUiInBackground() {
+  // ShowKeyboardInternal may trigger RootControllerWindow::ActiveKeyboard which
+  // will cause LoadKeyboardUiInBackground to potentially run even though the
+  // keyboard has been initialized.
+  if (state_ != KeyboardControllerState::INITIAL)
+    return;
+
   // The container window should have been created already when
   // |Shell::CreateKeyboard| is called.
   DCHECK(container_.get());
 
+  PopulateKeyboardContent(display::kInvalidDisplayId, false);
+}
+
+void KeyboardController::ShowKeyboardInternal(int64_t display_id) {
+  DCHECK(container_.get());
+  keyboard::MarkKeyboardLoadStarted();
+  PopulateKeyboardContent(display_id, true);
+}
+
+void KeyboardController::PopulateKeyboardContent(int64_t display_id,
+                                                 bool show_keyboard) {
   TRACE_EVENT0("vk", "ShowKeyboardInternal");
 
-  // Add the WebContents window to the container if it has not been added.
   if (container_->children().empty()) {
-    keyboard::MarkKeyboardLoadStarted();
+    // Add the WebContents window to the container if it hasn't already.
     aura::Window* keyboard = ui_->GetKeyboardWindow();
     keyboard->Show();
     container_->AddChild(keyboard);
@@ -563,7 +589,6 @@
   }
 
   ui_->ReloadKeyboardIfNeeded();
-
   if (layout_delegate_ != nullptr) {
     if (display_id != display::kInvalidDisplayId)
       layout_delegate_->MoveKeyboardToDisplay(display_id);
@@ -573,8 +598,12 @@
 
   if (keyboard_visible_) {
     return;
-  } else if (ui_->GetKeyboardWindow()->bounds().height() == 0) {
-    show_on_resize_ = true;
+  } else if (!show_keyboard ||
+             ui_->GetKeyboardWindow()->bounds().height() == 0) {
+    if (show_keyboard) {
+      // show the keyboard once loading is complete.
+      show_on_resize_ = true;
+    }
     ChangeState(KeyboardControllerState::LOADING_EXTENSION);
     return;
   }
@@ -600,11 +629,11 @@
            // KeyboardControllerTest.CloseKeyboard. Check if it's expected and
            // resolve it if not.
            || state_ == KeyboardControllerState::LOADING_EXTENSION
-           // TODO(oka): the state is INITIAL in
+           // TODO(oka): the state is HIDDEN in
            // VirtualKeyboardRootWindowControllerTest
            //     .EnsureCaretInWorkAreaWithMultipleDisplays.
            // Fix the test.
-           || state_ == KeyboardControllerState::INITIAL)
+           || state_ == KeyboardControllerState::HIDDEN)
         << StateToStr(state_);
     return;
   }
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 5fd0028..2ff06f2 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -52,7 +52,8 @@
   UNKNOWN = 0,
   // Keyboard has never been shown.
   INITIAL = 1,
-  // Waiting for an extension to be loaded and then move to SHOWING.
+  // Waiting for an extension to be loaded. Will move to HIDDEN if this is
+  // loading pre-emptively, otherwise will move to SHOWING.
   LOADING_EXTENSION = 2,
   // Keyboard is being shown via animation.
   SHOWING = 3,
@@ -81,7 +82,8 @@
   };
 
   // Takes ownership of |ui|.
-  explicit KeyboardController(KeyboardUI* ui, KeyboardLayoutDelegate* delegate);
+  explicit KeyboardController(std::unique_ptr<KeyboardUI> ui,
+                              KeyboardLayoutDelegate* delegate);
   ~KeyboardController() override;
 
   // Returns the container for the keyboard, which is owned by
@@ -127,6 +129,10 @@
   // |lock| is true.
   void ShowKeyboard(bool lock);
 
+  // Loads the keyboard UI contents in the background, but does not display
+  // the keyboard.
+  void LoadKeyboardUiInBackground();
+
   // Force the keyboard to show up in the specific display if not showing and
   // lock the keyboard
   void ShowKeyboardInDisplay(const int64_t display_id);
@@ -159,6 +165,9 @@
   // For access to Observer methods for simulation.
   friend class KeyboardControllerTest;
 
+  // For access to NotifyKeyboardLoadingComplete.
+  friend class KeyboardLayoutManager;
+
   // aura::WindowObserver overrides
   void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
   void OnWindowAddedToRootWindow(aura::Window* window) override;
@@ -177,8 +186,12 @@
   void OnTextInputStateChanged(const ui::TextInputClient* client) override;
   void OnShowImeIfNeeded() override;
 
+  // Notifies that the extension has completed loading
+  void NotifyKeyboardLoadingComplete();
+
   // Show virtual keyboard immediately with animation.
   void ShowKeyboardInternal(int64_t display_id);
+  void PopulateKeyboardContent(int64_t display_id, bool show_keyboard);
 
   // Returns true if keyboard is scheduled to hide.
   bool WillHideKeyboard() const;
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc
index b3f2dea..5822a8f 100644
--- a/ui/keyboard/keyboard_controller_unittest.cc
+++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -214,7 +214,6 @@
       : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::UI),
         number_of_calls_(0),
-        ui_(nullptr),
         keyboard_closed_(false) {}
   ~KeyboardControllerTest() override {}
 
@@ -232,9 +231,11 @@
     aura_test_helper_->SetUp(context_factory, context_factory_private);
     new wm::DefaultActivationClient(aura_test_helper_->root_window());
     focus_controller_.reset(new TestFocusController(root_window()));
-    ui_ = new TestKeyboardUI(aura_test_helper_->host()->GetInputMethod());
     layout_delegate_.reset(new TestKeyboardLayoutDelegate());
-    controller_.reset(new KeyboardController(ui_, layout_delegate_.get()));
+    controller_.reset(
+        new KeyboardController(base::MakeUnique<TestKeyboardUI>(
+                                   aura_test_helper_->host()->GetInputMethod()),
+                               layout_delegate_.get()));
     controller()->AddObserver(this);
 
     if (!GetParam()) {
@@ -254,7 +255,7 @@
   }
 
   aura::Window* root_window() { return aura_test_helper_->root_window(); }
-  KeyboardUI* ui() { return ui_; }
+  KeyboardUI* ui() { return controller_->ui(); }
   KeyboardController* controller() { return controller_.get(); }
 
   void ShowKeyboard() {
@@ -288,9 +289,9 @@
     input_method->SetFocusedTextInputClient(client);
     if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
       input_method->ShowImeIfNeeded();
-      if (ui_->GetKeyboardWindow()->bounds().height() == 0) {
+      if (controller_->ui()->GetKeyboardWindow()->bounds().height() == 0) {
         // Set initial bounds for test keyboard window.
-        ui_->GetKeyboardWindow()->SetBounds(
+        controller_->ui()->GetKeyboardWindow()->SetBounds(
             FullWidthKeyboardBoundsFromRootBounds(
                 root_window()->bounds(), kDefaultVirtualKeyboardHeight));
       }
@@ -302,7 +303,7 @@
   }
 
   bool ShouldEnableInsets(aura::Window* window) {
-    aura::Window* keyboard_window = ui_->GetKeyboardWindow();
+    aura::Window* keyboard_window = controller_->ui()->GetKeyboardWindow();
     return (keyboard_window->GetRootWindow() == window->GetRootWindow() &&
             keyboard::IsKeyboardOverscrollEnabled() &&
             keyboard_window->IsVisible() &&
@@ -318,7 +319,6 @@
  private:
   int number_of_calls_;
   gfx::Rect notified_bounds_;
-  KeyboardUI* ui_;
   std::unique_ptr<KeyboardLayoutDelegate> layout_delegate_;
   std::unique_ptr<KeyboardController> controller_;
   std::unique_ptr<ui::TextInputClient> test_text_input_client_;
diff --git a/ui/keyboard/keyboard_layout_manager.cc b/ui/keyboard/keyboard_layout_manager.cc
index 3efe6df23..5a79dc1d 100644
--- a/ui/keyboard/keyboard_layout_manager.cc
+++ b/ui/keyboard/keyboard_layout_manager.cc
@@ -80,8 +80,10 @@
   controller_->GetContainerWindow()->SetBounds(new_bounds);
   SetChildBoundsDirect(keyboard_, gfx::Rect(new_bounds.size()));
 
-  if (old_bounds.height() == 0 && child->bounds().height() != 0 &&
-      controller_->show_on_resize()) {
+  const bool container_had_size = old_bounds.height() != 0;
+  const bool child_has_size = child->bounds().height() != 0;
+
+  if (!container_had_size && child_has_size && controller_->show_on_resize()) {
     // The window height is set to 0 initially or before switch to an IME in a
     // different extension. Virtual keyboard window may wait for this bounds
     // change to correctly animate in.
@@ -97,6 +99,13 @@
       controller_->ShowKeyboard(false /* lock */);
     }
   } else {
+    if (!container_had_size && child_has_size &&
+        !controller_->keyboard_visible()) {
+      // When the child is layed out, the controller is not shown, but showing
+      // is not desired, this is indicative that the pre-load has completed.
+      controller_->NotifyKeyboardLoadingComplete();
+    }
+
     if (controller_->keyboard_mode() == FULL_WIDTH) {
       // We need to send out this notification only if keyboard is visible since
       // keyboard window is resized even if keyboard is hidden.
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index 377026c..99940ddeb 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -268,6 +268,7 @@
         "views/message_center_view_unittest.cc",
         "views/message_list_view_unittest.cc",
         "views/message_popup_collection_unittest.cc",
+        "views/notification_view_md_unittest.cc",
         "views/notification_view_unittest.cc",
         "views/notifier_settings_view_unittest.cc",
       ]
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 5426c6f..81b3a45 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -117,6 +117,8 @@
   explicit ItemView(const message_center::NotificationItem& item);
   ~ItemView() override;
 
+  const char* GetClassName() const override;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ItemView);
 };
@@ -143,6 +145,10 @@
 
 ItemView::~ItemView() = default;
 
+const char* ItemView::GetClassName() const {
+  return "ItemView";
+}
+
 // CompactTitleMessageView /////////////////////////////////////////////////////
 
 // CompactTitleMessageView shows notification title and message in a single
@@ -152,6 +158,8 @@
   explicit CompactTitleMessageView();
   ~CompactTitleMessageView() override;
 
+  const char* GetClassName() const override;
+
   void OnPaint(gfx::Canvas* canvas) override;
 
   void set_title(const base::string16& title) { title_ = title; }
@@ -167,7 +175,11 @@
   views::Label* message_view_ = nullptr;
 };
 
-CompactTitleMessageView::~CompactTitleMessageView() {}
+CompactTitleMessageView::~CompactTitleMessageView() = default;
+
+const char* CompactTitleMessageView::GetClassName() const {
+  return "CompactTitleMessageView";
+}
 
 CompactTitleMessageView::CompactTitleMessageView() {
   SetLayoutManager(new views::FillLayout());
@@ -230,6 +242,7 @@
   ~NotificationButtonMD() override;
 
   void SetText(const base::string16& text) override;
+  const char* GetClassName() const override;
 
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
@@ -260,6 +273,10 @@
   views::LabelButton::SetText(base::i18n::ToUpper(text));
 }
 
+const char* NotificationButtonMD::GetClassName() const {
+  return "NotificationButtonMD";
+}
+
 std::unique_ptr<views::InkDropHighlight>
 NotificationButtonMD::CreateInkDropHighlight() const {
   std::unique_ptr<views::InkDropHighlight> highlight =
@@ -315,10 +332,12 @@
   CreateOrUpdateIconView(notification);
   CreateOrUpdateSmallIconView(notification);
   CreateOrUpdateImageView(notification);
-  CreateOrUpdateActionButtonViews(notification);
   CreateOrUpdateCloseButtonView(notification);
   CreateOrUpdateSettingsButtonView(notification);
   UpdateViewForExpandedState(expanded_);
+  // Should be called at the last because SynthesizeMouseMoveEvent() requires
+  // everything is in the right location when called.
+  CreateOrUpdateActionButtonViews(notification);
 }
 
 NotificationViewMD::NotificationViewMD(MessageCenterController* controller,
@@ -483,8 +502,10 @@
 
 void NotificationViewMD::CreateOrUpdateTitleView(
     const Notification& notification) {
-  if (notification.type() == NOTIFICATION_TYPE_PROGRESS) {
-    left_content_->RemoveChildView(title_view_);
+  if (notification.title().empty() ||
+      notification.type() == NOTIFICATION_TYPE_PROGRESS) {
+    DCHECK(!title_view_ || left_content_->Contains(title_view_));
+    delete title_view_;
     title_view_ = nullptr;
     return;
   }
@@ -539,7 +560,9 @@
 void NotificationViewMD::CreateOrUpdateCompactTitleMessageView(
     const Notification& notification) {
   if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
-    left_content_->RemoveChildView(compact_title_message_view_);
+    DCHECK(!compact_title_message_view_ ||
+           left_content_->Contains(compact_title_message_view_));
+    delete compact_title_message_view_;
     compact_title_message_view_ = nullptr;
     return;
   }
@@ -556,7 +579,8 @@
 void NotificationViewMD::CreateOrUpdateProgressBarView(
     const Notification& notification) {
   if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
-    left_content_->RemoveChildView(progress_bar_view_);
+    DCHECK(!progress_bar_view_ || left_content_->Contains(progress_bar_view_));
+    delete progress_bar_view_;
     progress_bar_view_ = nullptr;
     header_row_->ClearProgress();
     return;
@@ -604,7 +628,8 @@
     const Notification& notification) {
   if (notification.type() == NOTIFICATION_TYPE_PROGRESS ||
       notification.type() == NOTIFICATION_TYPE_MULTIPLE) {
-    right_content_->RemoveChildView(icon_view_);
+    DCHECK(!icon_view_ || right_content_->Contains(icon_view_));
+    delete icon_view_;
     icon_view_ = nullptr;
     return;
   }
@@ -637,8 +662,8 @@
   if (notification.image().IsEmpty()) {
     if (image_container_) {
       DCHECK(image_view_);
-
-      left_content_->RemoveChildView(image_container_);
+      DCHECK(Contains(image_container_));
+      delete image_container_;
       image_container_ = NULL;
       image_view_ = NULL;
     } else {
@@ -696,11 +721,14 @@
     }
   }
 
-  if (new_buttons) {
-    // TODO(fukino): Investigate if this Layout() is necessary.
-    Layout();
+  // Inherit mouse hover state when action button views reset.
+  // If the view is not expanded, there should be no hover state.
+  if (new_buttons && expanded_) {
     views::Widget* widget = GetWidget();
-    if (widget != NULL) {
+    if (widget) {
+      // This Layout() is needed because button should be in the right location
+      // in the view hierarchy when SynthesizeMouseMoveEvent() is called.
+      Layout();
       widget->SetSize(widget->GetContentsView()->GetPreferredSize());
       GetWidget()->SynthesizeMouseMoveEvent();
     }
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 890165a..547d112d 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -64,6 +64,13 @@
   views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, CreateOrUpdateTest);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonsStateTest);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonCountTest);
+
+  friend class NotificationViewMDTest;
+
   void CreateOrUpdateViews(const Notification& notification);
 
   void CreateOrUpdateContextTitleView(const Notification& notification);
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
new file mode 100644
index 0000000..9baa68c
--- /dev/null
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -0,0 +1,501 @@
+// 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 "ui/message_center/views/notification_view_md.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/events/event_processor.h"
+#include "ui/events/event_utils.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/gfx/canvas.h"
+#include "ui/message_center/message_center_style.h"
+#include "ui/message_center/views/message_center_controller.h"
+#include "ui/message_center/views/notification_header_view.h"
+#include "ui/message_center/views/proportional_image_view.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/test/widget_test.h"
+
+namespace message_center {
+
+/* Test fixture ***************************************************************/
+
+// Used to fill bitmaps returned by CreateBitmap().
+static const SkColor kBitmapColor = SK_ColorGREEN;
+
+class NotificationViewMDTest : public views::ViewsTestBase,
+                               public MessageCenterController {
+ public:
+  NotificationViewMDTest();
+  ~NotificationViewMDTest() override;
+
+  // Overridden from ViewsTestBase:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Overridden from MessageCenterController:
+  void ClickOnNotification(const std::string& notification_id) override;
+  void RemoveNotification(const std::string& notification_id,
+                          bool by_user) override;
+  std::unique_ptr<ui::MenuModel> CreateMenuModel(
+      const NotifierId& notifier_id,
+      const base::string16& display_source) override;
+  bool HasClickedListener(const std::string& notification_id) override;
+  void ClickOnNotificationButton(const std::string& notification_id,
+                                 int button_index) override;
+  void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
+
+  NotificationViewMD* notification_view() const {
+    return notification_view_.get();
+  }
+  Notification* notification() const { return notification_.get(); }
+  views::Widget* widget() const {
+    DCHECK_EQ(widget_, notification_view()->GetWidget());
+    return widget_;
+  }
+
+ protected:
+  const gfx::Image CreateTestImage(int width, int height);
+  const SkBitmap CreateBitmap(int width, int height);
+  std::vector<ButtonInfo> CreateButtons(int number);
+
+  // Paints |view| and returns the size that the original image (which must have
+  // been created by CreateBitmap()) was scaled to.
+  gfx::Size GetImagePaintSize(ProportionalImageView* view);
+
+  void UpdateNotificationViews();
+  float GetNotificationSlideAmount() const;
+  bool IsRemoved(const std::string& notification_id) const;
+  void DispatchGesture(const ui::GestureEventDetails& details);
+  void BeginScroll();
+  void EndScroll();
+  void ScrollBy(int dx);
+  views::ImageButton* GetCloseButton();
+
+ private:
+  std::set<std::string> removed_ids_;
+
+  std::unique_ptr<RichNotificationData> data_;
+  std::unique_ptr<Notification> notification_;
+  std::unique_ptr<NotificationViewMD> notification_view_;
+  views::Widget* widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotificationViewMDTest);
+};
+
+NotificationViewMDTest::NotificationViewMDTest() = default;
+NotificationViewMDTest::~NotificationViewMDTest() = default;
+
+void NotificationViewMDTest::SetUp() {
+  views::ViewsTestBase::SetUp();
+  // Create a dummy notification.
+  data_.reset(new RichNotificationData());
+  notification_.reset(new Notification(
+      NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"),
+      base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
+      CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), GURL(),
+      NotifierId(NotifierId::APPLICATION, "extension_id"), *data_, nullptr));
+  notification_->set_small_image(CreateTestImage(16, 16));
+  notification_->set_image(CreateTestImage(320, 240));
+
+  // Then create a new NotificationView with that single notification.
+  // In the actual code path, this is instantiated by
+  // MessageViewFactory::Create.
+  // TODO(tetsui): Confirm that NotificationViewMD options are same as one
+  // created by the method.
+  notification_view_.reset(new NotificationViewMD(this, *notification_));
+  notification_view_->SetIsNested();
+  notification_view_->set_owned_by_client();
+
+  views::Widget::InitParams init_params(
+      CreateParams(views::Widget::InitParams::TYPE_POPUP));
+  widget_ = new views::Widget();
+  widget_->Init(init_params);
+  widget_->SetContentsView(notification_view_.get());
+  widget_->SetSize(notification_view_->GetPreferredSize());
+  widget_->Show();
+}
+
+void NotificationViewMDTest::TearDown() {
+  widget()->Close();
+  notification_view_.reset();
+  views::ViewsTestBase::TearDown();
+}
+
+void NotificationViewMDTest::ClickOnNotification(
+    const std::string& notification_id) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
+void NotificationViewMDTest::RemoveNotification(
+    const std::string& notification_id,
+    bool by_user) {
+  removed_ids_.insert(notification_id);
+}
+
+std::unique_ptr<ui::MenuModel> NotificationViewMDTest::CreateMenuModel(
+    const NotifierId& notifier_id,
+    const base::string16& display_source) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+  return nullptr;
+}
+
+bool NotificationViewMDTest::HasClickedListener(
+    const std::string& notification_id) {
+  return true;
+}
+
+void NotificationViewMDTest::ClickOnNotificationButton(
+    const std::string& notification_id,
+    int button_index) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
+void NotificationViewMDTest::ClickOnSettingsButton(
+    const std::string& notification_id) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
+void NotificationViewMDTest::UpdateNotificationSize(
+    const std::string& notification_id) {
+  widget()->SetSize(notification_view()->GetPreferredSize());
+}
+
+const gfx::Image NotificationViewMDTest::CreateTestImage(int width,
+                                                         int height) {
+  return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height));
+}
+
+const SkBitmap NotificationViewMDTest::CreateBitmap(int width, int height) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(width, height);
+  bitmap.eraseColor(kBitmapColor);
+  return bitmap;
+}
+
+std::vector<ButtonInfo> NotificationViewMDTest::CreateButtons(int number) {
+  ButtonInfo info(base::ASCIIToUTF16("Test button."));
+  info.icon = CreateTestImage(4, 4);
+  return std::vector<ButtonInfo>(number, info);
+}
+
+gfx::Size NotificationViewMDTest::GetImagePaintSize(
+    ProportionalImageView* view) {
+  CHECK(view);
+  if (view->bounds().IsEmpty())
+    return gfx::Size();
+
+  gfx::Size canvas_size = view->bounds().size();
+  gfx::Canvas canvas(canvas_size, 1.0 /* image_scale */, true /* is_opaque */);
+  static_assert(kBitmapColor != SK_ColorBLACK,
+                "The bitmap color must match the background color");
+  canvas.DrawColor(SK_ColorBLACK);
+  view->OnPaint(&canvas);
+
+  SkBitmap bitmap = canvas.GetBitmap();
+  // Incrementally inset each edge at its midpoint to find the bounds of the
+  // rect containing the image's color. This assumes that the image is
+  // centered in the canvas.
+  const int kHalfWidth = canvas_size.width() / 2;
+  const int kHalfHeight = canvas_size.height() / 2;
+  gfx::Rect rect(canvas_size);
+  while (rect.width() > 0 &&
+         bitmap.getColor(rect.x(), kHalfHeight) != kBitmapColor)
+    rect.Inset(1, 0, 0, 0);
+  while (rect.height() > 0 &&
+         bitmap.getColor(kHalfWidth, rect.y()) != kBitmapColor)
+    rect.Inset(0, 1, 0, 0);
+  while (rect.width() > 0 &&
+         bitmap.getColor(rect.right() - 1, kHalfHeight) != kBitmapColor)
+    rect.Inset(0, 0, 1, 0);
+  while (rect.height() > 0 &&
+         bitmap.getColor(kHalfWidth, rect.bottom() - 1) != kBitmapColor)
+    rect.Inset(0, 0, 0, 1);
+
+  return rect.size();
+}
+
+void NotificationViewMDTest::UpdateNotificationViews() {
+  notification_view()->UpdateWithNotification(*notification());
+}
+
+float NotificationViewMDTest::GetNotificationSlideAmount() const {
+  return notification_view_->GetSlideOutLayer()
+      ->transform()
+      .To2dTranslation()
+      .x();
+}
+
+bool NotificationViewMDTest::IsRemoved(
+    const std::string& notification_id) const {
+  return (removed_ids_.find(notification_id) != removed_ids_.end());
+}
+
+void NotificationViewMDTest::DispatchGesture(
+    const ui::GestureEventDetails& details) {
+  ui::test::EventGenerator generator(
+      notification_view()->GetWidget()->GetNativeWindow());
+  ui::GestureEvent event(0, 0, 0, ui::EventTimeForNow(), details);
+  generator.Dispatch(&event);
+}
+
+void NotificationViewMDTest::BeginScroll() {
+  DispatchGesture(ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+}
+
+void NotificationViewMDTest::EndScroll() {
+  DispatchGesture(ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+}
+
+void NotificationViewMDTest::ScrollBy(int dx) {
+  DispatchGesture(ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, dx, 0));
+}
+
+views::ImageButton* NotificationViewMDTest::GetCloseButton() {
+  return notification_view()->header_row_->close_button();
+}
+
+/* Unit tests *****************************************************************/
+
+// TODO(tetsui): Following tests are not yet ported from NotificationViewTest.
+// * CreateOrUpdateTestSettingsButton
+// * TestLineLimits
+// * TestImageSizing
+// * SettingsButtonTest
+// * ViewOrderingTest
+// * FormatContextMessageTest
+
+TEST_F(NotificationViewMDTest, CreateOrUpdateTest) {
+  EXPECT_NE(nullptr, notification_view()->title_view_);
+  EXPECT_NE(nullptr, notification_view()->message_view_);
+  EXPECT_NE(nullptr, notification_view()->icon_view_);
+  EXPECT_NE(nullptr, notification_view()->image_view_);
+
+  notification()->set_image(gfx::Image());
+  notification()->set_title(base::string16());
+  notification()->set_message(base::string16());
+  notification()->set_icon(gfx::Image());
+
+  notification_view()->CreateOrUpdateViews(*notification());
+
+  EXPECT_EQ(nullptr, notification_view()->title_view_);
+  EXPECT_EQ(nullptr, notification_view()->message_view_);
+  EXPECT_EQ(nullptr, notification_view()->image_view_);
+  // We still expect an icon view for all layouts.
+  EXPECT_NE(nullptr, notification_view()->icon_view_);
+}
+
+TEST_F(NotificationViewMDTest, TestIconSizing) {
+  // TODO(tetsui): Remove duplicated integer literal in CreateOrUpdateIconView.
+  const int kNotificationIconSize = 30;
+
+  notification()->set_type(NOTIFICATION_TYPE_SIMPLE);
+  ProportionalImageView* view = notification_view()->icon_view_;
+
+  // Icons smaller than the maximum size should remain unscaled.
+  notification()->set_icon(
+      CreateTestImage(kNotificationIconSize / 2, kNotificationIconSize / 4));
+  UpdateNotificationViews();
+  EXPECT_EQ(gfx::Size(kNotificationIconSize / 2, kNotificationIconSize / 4)
+                .ToString(),
+            GetImagePaintSize(view).ToString());
+
+  // Icons of exactly the intended icon size should remain unscaled.
+  notification()->set_icon(
+      CreateTestImage(kNotificationIconSize, kNotificationIconSize));
+  UpdateNotificationViews();
+  EXPECT_EQ(gfx::Size(kNotificationIconSize, kNotificationIconSize).ToString(),
+            GetImagePaintSize(view).ToString());
+
+  // Icons over the maximum size should be scaled down, maintaining proportions.
+  notification()->set_icon(
+      CreateTestImage(2 * kNotificationIconSize, 2 * kNotificationIconSize));
+  UpdateNotificationViews();
+  EXPECT_EQ(gfx::Size(kNotificationIconSize, kNotificationIconSize).ToString(),
+            GetImagePaintSize(view).ToString());
+
+  notification()->set_icon(
+      CreateTestImage(4 * kNotificationIconSize, 2 * kNotificationIconSize));
+  UpdateNotificationViews();
+  EXPECT_EQ(
+      gfx::Size(kNotificationIconSize, kNotificationIconSize / 2).ToString(),
+      GetImagePaintSize(view).ToString());
+}
+
+TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) {
+  notification()->set_buttons(CreateButtons(2));
+  notification_view()->CreateOrUpdateViews(*notification());
+  widget()->Show();
+
+  // Action buttons are hidden by collapsed state.
+  if (!notification_view()->expanded_)
+    notification_view()->ToggleExpanded();
+  EXPECT_TRUE(notification_view()->actions_row_->visible());
+
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[0]->state());
+
+  // Now construct a mouse move event 1 pixel inside the boundary of the action
+  // button.
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToWidget(notification_view()->action_buttons_[0],
+                                    &cursor_location);
+  ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
+                      ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  widget()->OnMouseEvent(&move);
+
+  EXPECT_EQ(views::CustomButton::STATE_HOVERED,
+            notification_view()->action_buttons_[0]->state());
+
+  notification_view()->CreateOrUpdateViews(*notification());
+
+  EXPECT_EQ(views::CustomButton::STATE_HOVERED,
+            notification_view()->action_buttons_[0]->state());
+
+  // Now construct a mouse move event 1 pixel outside the boundary of the
+  // widget.
+  cursor_location = gfx::Point(-1, -1);
+  move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
+                        ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  widget()->OnMouseEvent(&move);
+
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[0]->state());
+}
+
+TEST_F(NotificationViewMDTest, UpdateButtonCountTest) {
+  notification()->set_buttons(CreateButtons(2));
+  notification_view()->UpdateWithNotification(*notification());
+  widget()->Show();
+
+  // Action buttons are hidden by collapsed state.
+  if (!notification_view()->expanded_)
+    notification_view()->ToggleExpanded();
+  EXPECT_TRUE(notification_view()->actions_row_->visible());
+
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[0]->state());
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[1]->state());
+
+  // Now construct a mouse move event 1 pixel inside the boundary of the action
+  // button.
+  gfx::Point cursor_location(1, 1);
+  views::View::ConvertPointToScreen(notification_view()->action_buttons_[0],
+                                    &cursor_location);
+  ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
+                      ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  ui::EventDispatchDetails details =
+      views::test::WidgetTest::GetEventSink(widget())->OnEventFromSource(&move);
+  EXPECT_FALSE(details.dispatcher_destroyed);
+
+  EXPECT_EQ(views::CustomButton::STATE_HOVERED,
+            notification_view()->action_buttons_[0]->state());
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[1]->state());
+
+  notification()->set_buttons(CreateButtons(1));
+  notification_view()->UpdateWithNotification(*notification());
+
+  EXPECT_EQ(views::CustomButton::STATE_HOVERED,
+            notification_view()->action_buttons_[0]->state());
+  EXPECT_EQ(1u, notification_view()->action_buttons_.size());
+
+  // Now construct a mouse move event 1 pixel outside the boundary of the
+  // widget.
+  cursor_location = gfx::Point(-1, -1);
+  move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
+                        ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  widget()->OnMouseEvent(&move);
+
+  EXPECT_EQ(views::CustomButton::STATE_NORMAL,
+            notification_view()->action_buttons_[0]->state());
+}
+
+TEST_F(NotificationViewMDTest, SlideOut) {
+  ui::ScopedAnimationDurationScaleMode zero_duration_scope(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  UpdateNotificationViews();
+  std::string notification_id = notification()->id();
+
+  BeginScroll();
+  ScrollBy(-10);
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(-10.f, GetNotificationSlideAmount());
+  EndScroll();
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(0.f, GetNotificationSlideAmount());
+
+  BeginScroll();
+  ScrollBy(-200);
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(-200.f, GetNotificationSlideAmount());
+  EndScroll();
+  EXPECT_TRUE(IsRemoved(notification_id));
+}
+
+TEST_F(NotificationViewMDTest, SlideOutNested) {
+  ui::ScopedAnimationDurationScaleMode zero_duration_scope(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  UpdateNotificationViews();
+  notification_view()->SetIsNested();
+  std::string notification_id = notification()->id();
+
+  BeginScroll();
+  ScrollBy(-10);
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(-10.f, GetNotificationSlideAmount());
+  EndScroll();
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(0.f, GetNotificationSlideAmount());
+
+  BeginScroll();
+  ScrollBy(-200);
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_EQ(-200.f, GetNotificationSlideAmount());
+  EndScroll();
+  EXPECT_TRUE(IsRemoved(notification_id));
+}
+
+// Pinning notification is ChromeOS only feature.
+#if defined(OS_CHROMEOS)
+
+TEST_F(NotificationViewMDTest, SlideOutPinned) {
+  ui::ScopedAnimationDurationScaleMode zero_duration_scope(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  notification()->set_pinned(true);
+  UpdateNotificationViews();
+  std::string notification_id = notification()->id();
+
+  BeginScroll();
+  ScrollBy(-200);
+  EXPECT_FALSE(IsRemoved(notification_id));
+  EXPECT_LT(-200.f, GetNotificationSlideAmount());
+  EndScroll();
+  EXPECT_FALSE(IsRemoved(notification_id));
+}
+
+TEST_F(NotificationViewMDTest, Pinned) {
+  notification()->set_pinned(true);
+
+  UpdateNotificationViews();
+  EXPECT_FALSE(GetCloseButton()->visible());
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+}  // namespace message_center
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 36a73ff366..5047e94a 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/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index 762472b..765ef0e 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -26,6 +26,7 @@
 
 #if defined(OS_LINUX)
 #include "components/font_service/public/cpp/font_loader.h"
+#include "ui/gfx/platform_font_linux.h"
 #endif
 
 namespace views {
@@ -107,11 +108,15 @@
 #if defined(OS_LINUX)
   font_loader_ = sk_make_sp<font_service::FontLoader>(connector);
   SkFontConfigInterface::SetGlobal(font_loader_.get());
-#endif
 
-  // There is a bunch of static state in gfx::Font, by running this now,
-  // before any other apps load, we ensure all the state is set up.
-  gfx::Font();
+  // Initialize static default font, by running this now, before any other apps
+  // load, we ensure all the state is set up.
+  bool success = gfx::PlatformFontLinux::InitDefaultFont();
+
+  // If a remote service manager has shut down, initializing the font will fail.
+  if (!success)
+    return false;
+#endif  // defined(OS_LINUX)
 
   ui::InitializeInputMethodForTesting();
   return true;
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..bccc6b3 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,27 @@
   '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',
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-selector/compiled_resources2.gyp:iron-selector-extracted',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+        'cr_picture_types',
       ],
+      'target_name': 'cr_picture_list',
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'dependencies': [
+        '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..fead52c7 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..0d06a9e6 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_list.html b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.html
new file mode 100644
index 0000000..80f88ce
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.html
@@ -0,0 +1,84 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys/iron-a11y-keys.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
+<link rel="import" href="cr_picture_types.html">
+
+<dom-module id="cr-picture-list">
+  <template>
+    <style include="cr-shared-style">
+      img {
+        border-radius: 4px;
+        height: 64px;
+        margin: 8px;
+        padding: 2px;
+        vertical-align: top;
+        width: 64px;
+      }
+
+      img.iron-selected {
+        border: 2px solid var(--google-blue-500);
+        padding: 0;
+      }
+
+      iron-icon {
+        --iron-icon-fill-color: var(--google-grey-500);
+        --iron-icon-height: 32px;
+        --iron-icon-width: 32px;
+        border: 1px solid var(--google-grey-500);
+        border-radius: 4px;
+        margin: 8px;
+        padding: 17px;
+      }
+
+      iron-icon.iron-selected {
+        border: 2px solid var(--google-blue-500);
+        padding: 16px;
+      }
+
+      #container {
+        margin: -8px;
+        outline: none;
+      }
+    </style>
+
+    <div id="container" tabindex="0">
+      <iron-a11y-keys keys="up down left right space enter"
+          on-keys-pressed="onKeysPressed_">
+      </iron-a11y-keys>
+      <iron-selector id="selector" on-iron-activate="onIronActivate_"
+          selected-item="{{selectedItem}}" role="radiogroup">
+        <!-- Selects the camera as the picture source. -->
+        <iron-icon id="cameraImage" role="radio"
+            data-type$="[[selectionTypesEnum_.CAMERA]]"
+            icon="cr:camera-alt" title="[[takePhotoLabel]]"
+            hidden="[[!cameraPresent]]">
+        </iron-icon>
+        <!-- Selects the file picker as the picture source. -->
+        <iron-icon data-type$="[[selectionTypesEnum_.FILE]]" role="radio"
+            icon="cr:folder" title="[[chooseFileLabel]]">
+        </iron-icon>
+        <!-- Shows and selects the current profile picture. -->
+        <img id="profileImage" role="radio"
+            data-type$="[[selectionTypesEnum_.PROFILE]]"
+            src="[[profileImageUrl_]]" hidden="[[!profileImageUrl_]]"
+            title="[[profileImageLoadingLabel]]">
+        <!-- Shows and selects the previously selected ('old') picture. -->
+        <img id="oldImage" role="radio"
+            data-type$="[[selectionTypesEnum_.OLD]]"
+            src="[[oldImageUrl_]]" hidden="[[!oldImageUrl_]]"
+            title="[[oldImageLabel]]">
+        <!-- Shows the list of available images to select from. -->
+        <template is="dom-repeat" items="[[defaultImages]]">
+          <img role="radio"
+              data-type$="[[selectionTypesEnum_.DEFAULT]]"
+              data-index$="[[index]]" src="[[item.url]]" title="[[item.title]]">
+        </template>
+      </iron-selector>
+    </div>
+  </template>
+  <script src="cr_picture_list.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.js b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.js
new file mode 100644
index 0000000..af3db5f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.js
@@ -0,0 +1,204 @@
+// 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-list' is a Polymer element used to show a selectable list of
+ * profile pictures plus a camera selector, file picker, and the current
+ * profile image.
+ */
+
+Polymer({
+  is: 'cr-picture-list',
+
+  properties: {
+    cameraPresent: Boolean,
+
+    /**
+     * The default user images.
+     * @type {!Array<!{title: string, url: string}>}
+     */
+    defaultImages: {
+      type: Array,
+      observer: 'onDefaultImagesChanged_',
+    },
+
+    /** Strings provided by host */
+    chooseFileLabel: String,
+    oldImageLabel: String,
+    profileImageLabel: String,
+    profileImageLoadingLabel: String,
+    takePhotoLabel: String,
+
+    /**
+     * 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 {?CrPicture.ImageElement}
+     */
+    selectedItem: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * The url of the currently set profile picture image.
+     * @private {string}
+     */
+    profileImageUrl_: {
+      type: String,
+      value: 'chrome://theme/IDR_PROFILE_PICTURE_LOADING',
+    },
+
+    /**
+     * The url of the old image, which is either the existing image sourced from
+     * the camera, a file, or a deprecated default image.
+     * @private {string}
+     */
+    oldImageUrl_: {
+      type: String,
+      value: '',
+    },
+
+    /** @private */
+    selectionTypesEnum_: {
+      type: Object,
+      value: CrPicture.SelectionTypes,
+      readOnly: true,
+    },
+  },
+
+  /** @private {boolean} */
+  cameraSelected_: false,
+
+  /** @private {string} */
+  selectedImageUrl_: '',
+
+  /**
+   * 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 {?CrPicture.ImageElement}
+   */
+  fallbackImage_: null,
+
+  setFocus: function() {
+    this.$.container.focus();
+  },
+
+  /**
+   * @param {string} imageUrl
+   * @param {boolean} selected
+   */
+  setProfileImageUrl: function(imageUrl, selected) {
+    this.profileImageUrl_ = imageUrl;
+    this.$.profileImage.title = this.profileImageLabel;
+    if (!selected)
+      return;
+    this.setSelectedImage_(this.$.profileImage);
+  },
+
+  /**
+   * @param {string} imageUrl
+   */
+  setSelectedImageUrl(imageUrl) {
+    var image = this.$.selector.items.find(function(image) {
+      return image.src == imageUrl;
+    });
+    if (image) {
+      this.setSelectedImage_(image);
+      this.selectedImageUrl_ = '';
+    } else {
+      this.selectedImageUrl_ = imageUrl;
+    }
+  },
+
+  /**
+   * @param {string} imageUrl
+   */
+  setOldImageUrl(imageUrl) {
+    this.oldImageUrl_ = imageUrl;
+    if (imageUrl)
+      this.$.selector.select(this.$.selector.indexOf(this.$.oldImage));
+    else if (this.cameraSelected_)
+      this.$.selector.select(this.$.selector.indexOf(this.$.cameraImage));
+    else if (this.fallbackImage_)
+      this.selectImage_(this.fallbackImage_, true /* activate */);
+  },
+
+  /**
+   * @param {!CrPicture.ImageElement} image
+   */
+  setSelectedImage_(image) {
+    this.fallbackImage_ = image;
+    // If the user is currently taking a photo, do not change the focus.
+    if (!this.selectedItem ||
+        this.selectedItem.dataset.type != CrPicture.SelectionTypes.CAMERA) {
+      this.$.selector.select(this.$.selector.indexOf(image));
+    }
+  },
+
+  /** @private */
+  onDefaultImagesChanged_: function() {
+    if (this.selectedImageUrl_)
+      this.setSelectedImageUrl(this.selectedImageUrl_);
+  },
+
+  /**
+   * Handler for when accessibility-specific keys are pressed.
+   * @param {!{detail: !{key: string, keyboardEvent: Object}}} e
+   */
+  onKeysPressed_: function(e) {
+    if (!this.selectedItem)
+      return;
+
+    var selector = /** @type {IronSelectorElement} */ (this.$.selector);
+    var prevSelected = this.selectedItem;
+    var activate = false;
+    switch (e.detail.key) {
+      case 'enter':
+      case 'space':
+        activate = true;
+        break;
+      case 'up':
+      case 'left':
+        do {
+          selector.selectPrevious();
+        } while (this.selectedItem.hidden && this.selectedItem != prevSelected);
+        break;
+      case 'down':
+      case 'right':
+        do {
+          selector.selectNext();
+        } while (this.selectedItem.hidden && this.selectedItem != prevSelected);
+        break;
+      default:
+        return;
+    }
+    this.selectImage_(this.selectedItem, activate);
+    e.detail.keyboardEvent.preventDefault();
+  },
+
+  /**
+   * @param {!CrPicture.ImageElement} selected
+   * @param {boolean} activate
+   * @private
+   */
+  selectImage_(selected, activate) {
+    this.cameraSelected_ =
+        selected.dataset.type == CrPicture.SelectionTypes.CAMERA;
+    this.selectedItem = selected;
+    if (activate && selected.dataset.type == CrPicture.SelectionTypes.OLD)
+      this.fire('discard-image');
+    else if (activate || selected.dataset.type != CrPicture.SelectionTypes.FILE)
+      this.fire('image-activate', selected);
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onIronActivate_: function(event) {
+    this.selectImage_(event.detail.item, true /* activate */);
+  },
+});
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/cr_action_menu/cr_action_menu.js b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
index 33414bd3..181936d 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
@@ -89,10 +89,10 @@
     width: 0,
     anchorAlignmentX: AnchorAlignment.AFTER_START,
     anchorAlignmentY: AnchorAlignment.AFTER_START,
-    minX: doc.scrollLeft,
-    minY: doc.scrollTop,
-    maxX: doc.scrollLeft + window.innerWidth,
-    maxY: doc.scrollTop + window.innerHeight,
+    minX: 0,
+    minY: 0,
+    maxX: 0,
+    maxY: 0,
   };
 }
 
@@ -189,7 +189,8 @@
     var i = 0;
     do {
       var target = e.path[i++];
-      if (target.classList && target.classList.contains('dropdown-item')) {
+      if (target.classList && target.classList.contains('dropdown-item') &&
+          !target.disabled) {
         target.focus();
         return;
       }
@@ -253,22 +254,8 @@
     // accurate for where the menu should be shown.
     this.anchorElement_.scrollIntoViewIfNeeded();
 
-    // Save the scroll position that ensures the anchor element is onscreen.
-    var doc = document.scrollingElement;
-    var scrollLeft = doc.scrollLeft;
-    var scrollTop = doc.scrollTop;
-
-    // Reset position so that layout isn't affected by the previous position,
-    // and so that the dialog is positioned at the top-start corner of the
-    // document.
-    this.resetStyle_();
-
-    // Show the dialog which will focus the top-start of the body. This makes
-    // the client rect calculation relative to the top-start of the body.
-    this.showModal();
-
     var rect = this.anchorElement_.getBoundingClientRect();
-    this.positionDialog_(/** @type {ShowConfig} */ (Object.assign(
+    this.showAtPosition(/** @type {ShowConfig} */ (Object.assign(
         {
           top: rect.top,
           left: rect.left,
@@ -276,18 +263,8 @@
           width: rect.width,
           // Default to anchoring towards the left.
           anchorAlignmentX: AnchorAlignment.BEFORE_END,
-          minX: scrollLeft,
-          minY: scrollTop,
-          maxX: scrollLeft + window.innerWidth,
-          maxY: scrollTop + window.innerHeight,
         },
         opt_config)));
-
-    // Restore the scroll position.
-    doc.scrollTop = scrollTop;
-    doc.scrollLeft = scrollLeft;
-
-    this.addCloseListeners_();
   },
 
   /**
@@ -295,7 +272,8 @@
    * specified as an X and Y alignment which represents a point in the anchor
    * where the menu will align to, which can have the menu either before or
    * after the given point in each axis. Center alignment places the center of
-   * the menu in line with the center of the anchor.
+   * the menu in line with the center of the anchor. Coordinates are relative to
+   * the top-left of the viewport.
    *
    *            y-start
    *         _____________
@@ -317,9 +295,32 @@
    * @param {!ShowConfig} config
    */
   showAtPosition: function(config) {
+    // Save the scroll position of the viewport.
+    var doc = document.scrollingElement;
+    var scrollLeft = doc.scrollLeft;
+    var scrollTop = doc.scrollTop;
+
+    // Reset position so that layout isn't affected by the previous position,
+    // and so that the dialog is positioned at the top-start corner of the
+    // document.
     this.resetStyle_();
     this.showModal();
-    this.positionDialog_(config);
+
+    config.top += scrollTop;
+    config.left += scrollLeft;
+
+    this.positionDialog_(/** @type {ShowConfig} */ (Object.assign(
+        {
+          minX: scrollLeft,
+          minY: scrollTop,
+          maxX: scrollLeft + doc.clientWidth,
+          maxY: scrollTop + doc.clientHeight,
+        },
+        config)));
+
+    // Restore the scroll position.
+    doc.scrollTop = scrollTop;
+    doc.scrollLeft = scrollLeft;
     this.addCloseListeners_();
   },
 
@@ -331,6 +332,8 @@
   },
 
   /**
+   * Position the dialog using the coordinates in config. Coordinates are
+   * relative to the top-left of the viewport when scrolled to (0, 0).
    * @param {!ShowConfig} config
    * @private
    */
@@ -351,7 +354,8 @@
         left, right, this.offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
 
     if (rtl) {
-      var menuRight = document.body.scrollWidth - menuLeft - this.offsetWidth;
+      var menuRight =
+          document.scrollingElement.clientWidth - menuLeft - this.offsetWidth;
       this.style.right = menuRight + 'px';
     } else {
       this.style.left = menuLeft + 'px';
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 3b5bf6d0..d6d5d14 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -48,6 +48,24 @@
     <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_LIST_HTML"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.html"
+               type="chrome_html" />
+    <structure name="IDR_CR_ELEMENTS_CHROMEOS_CHANGE_PICTURE_CR__PICTURE_LIST_JS"
+               file="../../webui/resources/cr_elements/chromeos/change_picture/cr_picture_list.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;